func (this *State) ExchangeRateAuthorityIsValid(e interfaces.IEBEntry) bool { // convert the conf quthority address into a authorityAddress := base58.Decode(this.ExchangeRateAuthorityAddress) ecPubPrefix := []byte{0x59, 0x2a} if !bytes.Equal(authorityAddress[:2], ecPubPrefix) { fmt.Errorf("Invalid Entry Credit Private Address") return false } pub := new([32]byte) copy(pub[:], authorityAddress[2:34]) // in case verify can't handle empty public key if this.ExchangeRateAuthorityAddress == "" { return false } sig := new([64]byte) externalIds := e.ExternalIDs() // check for number of ext ids if len(externalIds) < 1 { return false } copy(sig[:], externalIds[0]) // First ext id needs to be the signature of the content if !ed.VerifyCanonical(pub, e.GetContent(), sig) { return false } return true }
func registerIdentityAsServer(entry interfaces.IEBEntry, height uint32, st *State) error { extIDs := entry.ExternalIDs() if len(extIDs) == 0 { return errors.New("Identity Error Register Identity: Invalid external ID length") } if bytes.Compare([]byte{0x00}, extIDs[0]) != 0 || // Version !CheckExternalIDsLength(extIDs, []int{1, 26, 32, 33, 64}) { // Signiture return errors.New("Identity Error Register Identity: Invalid external ID length") } chainID := entry.GetChainID() IdentityIndex := st.isIdentityChain(chainID) if IdentityIndex == -1 { IdentityIndex = st.CreateBlankFactomIdentity(chainID) } sigmsg, err := AppendExtIDs(extIDs, 0, 2) if err != nil { return err } else { // Verify Signature idKey := st.Identities[IdentityIndex].Key1 if CheckSig(idKey, extIDs[3][1:33], sigmsg, extIDs[4]) { st.Identities[IdentityIndex].ManagementRegistered = height st.Identities[IdentityIndex].ManagementChainID = primitives.NewHash(extIDs[2][:32]) } else { return errors.New("New Management Chain Register for identity [" + chainID.String()[:10] + "] is invalid. Bad signiture") } } return nil }
// AddEBEntry creates a new Entry Block Entry from the provided Factom Entry // and adds it to the Entry Block Body. func (e *EBlock) AddEBEntry(entry interfaces.IEBEntry) error { e.Body.EBEntries = append(e.Body.EBEntries, entry.GetHash()) if err := e.BuildHeader(); err != nil { return err } return nil }
func addIdentity(entry interfaces.IEBEntry, height uint32, st *State) error { extIDs := entry.ExternalIDs() // This check is here to prevent possible index out of bounds with extIDs[:6] if len(extIDs) != 7 { return errors.New("Identity Error Create Management: Invalid external ID length") } if bytes.Compare([]byte{0x00}, extIDs[0]) != 0 || // Version !CheckExternalIDsLength(extIDs[:6], []int{1, 14, 32, 32, 32, 32}) { // Nonce return errors.New("Identity Error Create Identity Chain: Invalid external ID length") } chainID := entry.GetChainID() IdentityIndex := st.isIdentityChain(chainID) if IdentityIndex == -1 { IdentityIndex = st.CreateBlankFactomIdentity(chainID) } h := primitives.NewHash(extIDs[2]) st.Identities[IdentityIndex].Key1 = h h = primitives.NewHash(extIDs[3]) st.Identities[IdentityIndex].Key2 = h h = primitives.NewHash(extIDs[4]) st.Identities[IdentityIndex].Key3 = h h = primitives.NewHash(extIDs[5]) st.Identities[IdentityIndex].Key4 = h st.Identities[IdentityIndex].IdentityCreated = height return nil }
func registerFactomIdentity(entry interfaces.IEBEntry, chainID interfaces.IHash, height uint32, st *State) error { extIDs := entry.ExternalIDs() if len(extIDs) == 0 { return errors.New("Identity Error Register Identity: Invalid external ID length") } if bytes.Compare([]byte{0x00}, extIDs[0]) != 0 || // Version !CheckExternalIDsLength(extIDs, []int{1, 24, 32, 33, 64}) { // Signiture return errors.New("Identity Error Register Identity: Invalid external ID length") } // find the Identity index from the chain id in the external id. add this chainID as the management id idChain := primitives.NewHash(extIDs[2]) IdentityIndex := st.isIdentityChain(idChain) if IdentityIndex == -1 { IdentityIndex = st.CreateBlankFactomIdentity(idChain) } sigmsg, err := AppendExtIDs(extIDs, 0, 2) if err != nil { return err } else { // Verify Signature idKey := st.Identities[IdentityIndex].Key1 if CheckSig(idKey, extIDs[3][1:33], sigmsg, extIDs[4]) { st.Identities[IdentityIndex].ManagementRegistered = height } else { return errors.New("New Management Chain Register for identity [" + chainID.String()[:10] + "] is invalid. Bad signiture") } } st.Identities[IdentityIndex].IdentityRegistered = height return nil }
// NewChainID generates a ChainID from an entry. ChainID = primitives.Sha(Sha(ExtIDs[0]) + // Sha(ExtIDs[1] + ... + Sha(ExtIDs[n])) func NewChainID(e interfaces.IEBEntry) interfaces.IHash { id := new(primitives.Hash) sum := sha256.New() for _, v := range e.ExternalIDs() { x := sha256.Sum256(v) sum.Write(x[:]) } id.SetBytes(sum.Sum(nil)) return id }
// InsertEntry inserts an entry func (db *Overlay) InsertEntry(entry interfaces.IEBEntry) error { if entry == nil { return nil } //Entries are saved in buckets represented by their chainID for easy batch loading //They are also indexed in ENTRY bucket by their hash that points to their chainID //So they can be loaded in two load operations without needing to know their chainID batch := []interfaces.Record{} batch = append(batch, interfaces.Record{entry.GetChainID().Bytes(), entry.DatabasePrimaryIndex().Bytes(), entry}) batch = append(batch, interfaces.Record{ENTRY, entry.DatabasePrimaryIndex().Bytes(), entry.GetChainIDHash()}) return db.PutInBatch(batch) }
// AddEBEntry creates a new Entry Block Entry from the provided Factom Entry // and adds it to the Entry Block Body. func (e *EBlock) AddEBEntry(entry interfaces.IEBEntry) error { e.Body.EBEntries = append(e.Body.EBEntries, entry.GetHash()) return nil }
func registerAnchorSigningKey(entry interfaces.IEBEntry, initial bool, height uint32, st *State, BlockChain string) error { extIDs := entry.ExternalIDs() if bytes.Compare([]byte{0x00}, extIDs[0]) != 0 || !CheckExternalIDsLength(extIDs, []int{1, 15, 32, 1, 1, 20, 8, 33, 64}) { return errors.New("Identity Error Anchor Key: Invalid external ID length") } subChainID := entry.GetChainID() chainID := new(primitives.Hash) chainID.SetBytes(extIDs[2][:32]) IdentityIndex := st.isIdentityChain(chainID) if IdentityIndex == -1 { return errors.New("Identity Error: This cannot happen. New Bitcoin Key to nonexistent identity") } if !st.Identities[IdentityIndex].ManagementChainID.IsSameAs(subChainID) { return errors.New("Identity Error: Entry was not placed in the correct management chain") } var ask []AnchorSigningKey var newAsk []AnchorSigningKey var oneAsk AnchorSigningKey ask = st.Identities[IdentityIndex].AnchorKeys newAsk = make([]AnchorSigningKey, len(ask)+1) oneAsk.BlockChain = BlockChain oneAsk.KeyLevel = extIDs[3][0] oneAsk.KeyType = extIDs[4][0] oneAsk.SigningKey = extIDs[5] contains := false for i := 0; i < len(ask); i++ { if ask[i].KeyLevel == oneAsk.KeyLevel && strings.Compare(ask[i].BlockChain, oneAsk.BlockChain) == 0 { contains = true ask[i] = oneAsk } else { newAsk[i] = ask[i] } } newAsk[len(ask)] = oneAsk sigmsg, err := AppendExtIDs(extIDs, 0, 6) if err != nil { return err } else { // Verify Signature idKey := st.Identities[IdentityIndex].Key1 if CheckSig(idKey, extIDs[7][1:33], sigmsg, extIDs[8]) { var key [20]byte if len(extIDs[5]) != 20 { return errors.New("New Anchor key for identity [" + chainID.String()[:10] + "] is invalid length") } dbase := st.GetAndLockDB() dblk, err := dbase.FetchDBlockByHeight(height) st.UnlockDB() if err == nil && dblk != nil && dblk.GetHeader().GetTimestamp().GetTimeSeconds() != 0 { if !CheckTimestamp(extIDs[6], dblk.GetHeader().GetTimestamp().GetTimeSeconds()) { return errors.New("New Anchor key for identity [" + chainID.String()[:10] + "] timestamp is too old") } } else { if !CheckTimestamp(extIDs[6], st.GetTimestamp().GetTimeSeconds()) { return errors.New("New Anchor key for identity [" + chainID.String()[:10] + "] timestamp is too old") } } if contains { st.Identities[IdentityIndex].AnchorKeys = ask } else { st.Identities[IdentityIndex].AnchorKeys = newAsk } // Add to admin block status := st.Identities[IdentityIndex].Status if !initial && statusIsFedOrAudit(status) && st.GetLeaderVM() == st.ComputeVMIndex(entry.GetChainID().Bytes()) { copy(key[:20], extIDs[5][:20]) extIDs[5] = append(extIDs[5], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}...) key := primitives.NewHash(extIDs[5]) msg := messages.NewChangeServerKeyMsg(st, chainID, constants.TYPE_ADD_BTC_ANCHOR_KEY, extIDs[3][0], extIDs[4][0], key) err := msg.(*messages.ChangeServerKeyMsg).Sign(st.serverPrivKey) if err != nil { return errors.New("New Block Signing key for identity [" + chainID.String()[:10] + "] Error: cannot sign msg") } st.InMsgQueue() <- msg } } else { return errors.New("New Anchor key for identity [" + chainID.String()[:10] + "] is invalid. Bad signiture") } } return nil }
func updateMatryoshkaHash(entry interfaces.IEBEntry, initial bool, height uint32, st *State) error { extIDs := entry.ExternalIDs() if len(extIDs) == 0 { return errors.New("Identity Error MHash: Invalid external ID length") } if bytes.Compare([]byte{0x00}, extIDs[0]) != 0 || // Version !CheckExternalIDsLength(extIDs, []int{1, 19, 32, 32, 8, 33, 64}) { // Signiture return errors.New("Identity Error MHash: Invalid external ID length") } chainID := new(primitives.Hash) chainID.SetBytes(extIDs[2][:32]) subChainID := entry.GetChainID() IdentityIndex := st.isIdentityChain(chainID) if IdentityIndex == -1 { return errors.New("Identity Error: This cannot happen. New Matryoshka Hash to nonexistent identity") } if !st.Identities[IdentityIndex].ManagementChainID.IsSameAs(subChainID) { return errors.New("Identity Error: Entry was not placed in the correct management chain") } sigmsg, err := AppendExtIDs(extIDs, 0, 4) if err != nil { //log.Printfln("Identity Error:", err) return nil } else { // Verify Signature idKey := st.Identities[IdentityIndex].Key1 if CheckSig(idKey, extIDs[5][1:33], sigmsg, extIDs[6]) { // Check MHash length if len(extIDs[3]) != 32 { return errors.New("New Matryoshka Hash for identity [" + chainID.String()[:10] + "] is invalid length") } dbase := st.GetAndLockDB() dblk, err := dbase.FetchDBlockByHeight(height) st.UnlockDB() if err == nil && dblk != nil && dblk.GetHeader().GetTimestamp().GetTimeSeconds() != 0 { if !CheckTimestamp(extIDs[4], dblk.GetHeader().GetTimestamp().GetTimeSeconds()) { return errors.New("New Matryoshka Hash for identity [" + chainID.String()[:10] + "] timestamp is too old") } } else { if !CheckTimestamp(extIDs[4], st.GetTimestamp().GetTimeSeconds()) { return errors.New("New Matryoshka Hash for identity [" + chainID.String()[:10] + "] timestamp is too old") } } mhash := primitives.NewHash(extIDs[3]) st.Identities[IdentityIndex].MatryoshkaHash = mhash // Add to admin block status := st.Identities[IdentityIndex].Status if !initial && statusIsFedOrAudit(status) && st.GetLeaderVM() == st.ComputeVMIndex(entry.GetChainID().Bytes()) { //if st.LeaderPL.VMIndexFor(constants.ADMIN_CHAINID) == st.GetLeaderVM() { msg := messages.NewChangeServerKeyMsg(st, chainID, constants.TYPE_ADD_MATRYOSHKA, 0, 0, mhash) err := msg.(*messages.ChangeServerKeyMsg).Sign(st.serverPrivKey) if err != nil { return errors.New("New Block Signing key for identity [" + chainID.String()[:10] + "] Error: cannot sign msg") } //log.Printfln("DEBUG: MHash ChangeServer Message Sent") st.InMsgQueue() <- msg //} } } else { return errors.New("New Matryoshka Hash for identity [" + chainID.String()[:10] + "] is invalid. Bad signiture") } } return nil }
func registerBlockSigningKey(entry interfaces.IEBEntry, initial bool, height uint32, st *State) error { extIDs := entry.ExternalIDs() if len(extIDs) == 0 { return errors.New("Identity Error Block Signing Key: Invalid external ID length") } if bytes.Compare([]byte{0x00}, extIDs[0]) != 0 || // Version !CheckExternalIDsLength(extIDs, []int{1, 21, 32, 32, 8, 33, 64}) { return errors.New("Identity Error Block Signing Key: Invalid external ID length") } subChainID := entry.GetChainID() chainID := new(primitives.Hash) chainID.SetBytes(extIDs[2][:32]) IdentityIndex := st.isIdentityChain(chainID) if IdentityIndex == -1 { return errors.New("Identity Error: This cannot happen. New block signing key to nonexistent identity") } if !st.Identities[IdentityIndex].ManagementChainID.IsSameAs(subChainID) { return errors.New("Identity Error: Entry was not placed in the correct management chain") } sigmsg, err := AppendExtIDs(extIDs, 0, 4) if err != nil { return err } else { //verify Signature idKey := st.Identities[IdentityIndex].Key1 if CheckSig(idKey, extIDs[5][1:33], sigmsg, extIDs[6]) { // Check block key length if len(extIDs[3]) != 32 { return errors.New("New Block Signing key for identity [" + chainID.String()[:10] + "] is invalid length") } dbase := st.GetAndLockDB() dblk, err := dbase.FetchDBlockByHeight(height) st.UnlockDB() if err == nil && dblk != nil && dblk.GetHeader().GetTimestamp().GetTimeSeconds() != 0 { if !CheckTimestamp(extIDs[4], dblk.GetHeader().GetTimestamp().GetTimeSeconds()) { return errors.New("New Block Signing key for identity [" + chainID.String()[:10] + "] timestamp is too old") } } else { if !CheckTimestamp(extIDs[4], st.GetTimestamp().GetTimeSeconds()) { return errors.New("New Block Signing key for identity [" + chainID.String()[:10] + "] timestamp is too old") } } st.Identities[IdentityIndex].SigningKey = primitives.NewHash(extIDs[3]) // Add to admin block status := st.Identities[IdentityIndex].Status if !initial && statusIsFedOrAudit(status) && st.GetLeaderVM() == st.ComputeVMIndex(entry.GetChainID().Bytes()) { key := primitives.NewHash(extIDs[3]) msg := messages.NewChangeServerKeyMsg(st, chainID, constants.TYPE_ADD_FED_SERVER_KEY, 0, 0, key) err := msg.(*messages.ChangeServerKeyMsg).Sign(st.serverPrivKey) if err != nil { return errors.New("New Block Signing key for identity [" + chainID.String()[:10] + "] Error: cannot sign msg") } st.InMsgQueue() <- msg } } else { return errors.New("New Block Signing key for identity [" + chainID.String()[:10] + "] is invalid. Bad signiture") } } return nil }
func LoadIdentityByEntry(ent interfaces.IEBEntry, st *State, height uint32, initial bool) { if ent == nil { return } hs := ent.GetChainID().String() cid := ent.GetChainID() if st.isIdentityChain(cid) == -1 { if st.isAuthorityChain(cid) != -1 { // The authority exists, but the Identity does not. This could be an issue if a // server changes their key as we would not notice the change } return } if hs[0:60] != "000000000000000000000000000000000000000000000000000000000000" { //ignore minute markers if len(ent.ExternalIDs()) > 1 { if string(ent.ExternalIDs()[1]) == "Register Server Management" { registerIdentityAsServer(ent, height, st) } else if string(ent.ExternalIDs()[1]) == "New Block Signing Key" { if len(ent.ExternalIDs()) == 7 { registerBlockSigningKey(ent, initial, height, st) } } else if string(ent.ExternalIDs()[1]) == "New Bitcoin Key" { if len(ent.ExternalIDs()) == 9 { registerAnchorSigningKey(ent, initial, height, st, "BTC") } } else if string(ent.ExternalIDs()[1]) == "New Matryoshka Hash" { if len(ent.ExternalIDs()) == 7 { updateMatryoshkaHash(ent, initial, height, st) } } else if len(ent.ExternalIDs()) > 1 && string(ent.ExternalIDs()[1]) == "Identity Chain" { addIdentity(ent, height, st) } else if len(ent.ExternalIDs()) > 1 && string(ent.ExternalIDs()[1]) == "Server Management" { if len(ent.ExternalIDs()) == 4 { updateManagementKey(ent, height, st) } } } } }