<commit_before>package pkc

import (
	"bytes"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
)

type PubKey struct {
	Id  string
	Key *rsa.PublicKey
}

type KeyChain struct {
	Private *rsa.PrivateKey
	Public  []*PubKey
}

var ErrInvalidKeyChain = fmt.Errorf("invalid keychain")

// NewKeyChain sets up a new keychain based on the RSA private key passed
// in. It ensures the returned keychain is valid.
func NewKeyChain(prv *rsa.PrivateKey) (kc *KeyChain, err error) {
	if err = prv.Validate(); err != nil {
		return
	}
	kc = new(KeyChain)
	kc.Private = prv
	kc.Public = make([]*PubKey, 0)
	return
}

// ImportKeyChain imports a keychain from a PEM file, and ensures the
// returned KeyChain is valid.
func ImportKeyChain(filename string) (kc *KeyChain, err error) {
	var keychain KeyChain
	pubs := make([]*PubKey, 0)

	in, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}

	for {
		var blk *pem.Block
		blk, in = pem.Decode(in)
		if blk == nil {
			break
		}
		switch blk.Type {
		case "RSA PRIVATE KEY":
			if keychain.Private != nil {
				err = ErrInvalidKeyChain
				return
			}
			keychain.Private, err = x509.ParsePKCS1PrivateKey(blk.Bytes)
			if err != nil {
				err = ErrInvalidKeyChain
				return
			}
		case "RSA PUBLIC KEY":
			var inpub interface{}
			inpub, err = x509.ParsePKIXPublicKey(blk.Bytes)
			if err != nil {
				return
			}

			pubs = append(pubs, &PubKey{blk.Headers["id"], inpub.(*rsa.PublicKey)})
		}
		if in == nil || len(in) == 0 {
			break
		}
	}
	if err == nil {
		keychain.Public = pubs
		kc = &keychain
	}
	return
}

// AddPublic adds a public key to the keychain, and adds the string identifier
// to the structure.
func (kc *KeyChain) AddPublic(id string, pub *rsa.PublicKey) {
	if pub == nil {
		return
	}
	for _, pk := range kc.Public {
		if pk.Id == id {
			pk.Key = pub
			return
		}
	}
	kc.Public = append(kc.Public, &PubKey{id, pub})
}<commit_msg>Ignore empty identities when checking for duplicates.<commit_after>package pkc

import (
	"bytes"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
)

type PubKey struct {
	Id  string
	Key *rsa.PublicKey
}

type KeyChain struct {
	Private *rsa.PrivateKey
	Public  []*PubKey
}

var ErrInvalidKeyChain = fmt.Errorf("invalid keychain")

// NewKeyChain sets up a new keychain based on the RSA private key passed
// in. It ensures the returned keychain is valid.
func NewKeyChain(prv *rsa.PrivateKey) (kc *KeyChain, err error) {
	if err = prv.Validate(); err != nil {
		return
	}
	kc = new(KeyChain)
	kc.Private = prv
	kc.Public = make([]*PubKey, 0)
	return
}

// ImportKeyChain imports a keychain from a PEM file, and ensures the
// returned KeyChain is valid.
func ImportKeyChain(filename string) (kc *KeyChain, err error) {
	var keychain KeyChain
	pubs := make([]*PubKey, 0)

	in, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}

	for {
		var blk *pem.Block
		blk, in = pem.Decode(in)
		if blk == nil {
			break
		}
		switch blk.Type {
		case "RSA PRIVATE KEY":
			if keychain.Private != nil {
				err = ErrInvalidKeyChain
				return
			}
			keychain.Private, err = x509.ParsePKCS1PrivateKey(blk.Bytes)
			if err != nil {
				err = ErrInvalidKeyChain
				return
			}
		case "RSA PUBLIC KEY":
			var inpub interface{}
			inpub, err = x509.ParsePKIXPublicKey(blk.Bytes)
			if err != nil {
				return
			}

			pubs = append(pubs, &PubKey{blk.Headers["id"], inpub.(*rsa.PublicKey)})
		}
		if in == nil || len(in) == 0 {
			break
		}
	}
	if err == nil {
		keychain.Public = pubs
		kc = &keychain
	}
	return
}

// AddPublic adds a public key to the keychain, and adds the string identifier
// to the structure.
func (kc *KeyChain) AddPublic(id string, pub *rsa.PublicKey) {
	if pub == nil {
		return
	}
	for _, pk := range kc.Public {
		if id != "" && pk.Id == id {
			pk.Key = pub
			return
		}
	}
	kc.Public = append(kc.Public, &PubKey{id, pub})
}
{'fraction_non_alphanumeric': 0.12474279835390946, 'fraction_numerical': 0.006687242798353909, 'mean_word_length': 3.0936842105263156, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, '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': '3273298', 'n_tokens_mistral': 1598, 'n_tokens_neox': 1441, 'n_words': 425}