identity.go 3.14 KiB
package identity
import (
"crypto/ed25519"
"crypto/sha256"
"encoding/hex"
"github.com/iotaledger/autopeering-sim/peer"
)
type Identity struct {
Identifier peer.ID
StringIdentifier string
PublicKey ed25519.PublicKey
privateKey ed25519.PrivateKey
}
// Creates a new identity based on the given public key.
func NewPublicIdentity(publicKey ed25519.PublicKey) *Identity {
identifier := sha256.Sum256(publicKey)
return &Identity{
Identifier: identifier,
StringIdentifier: hex.EncodeToString(identifier[:8]),
PublicKey: publicKey,
privateKey: nil,
}
}
// Generates a identity based on a newly generated public/private key pair.
// It will panic if no such pair could be generated.
func GeneratePrivateIdentity() *Identity {
publicKey, privateKey, err := ed25519.GenerateKey(nil)
if err != nil {
panic("identity: failed generating key: " + err.Error())
}
return newPrivateIdentity(publicKey, privateKey)
}
// Sign signs the message with privateKey and returns the message plus the signature.
func (id *Identity) AddSignature(msg []byte) []byte {
signatureStart := len(msg)
signature := ed25519.Sign(id.privateKey, msg)
data := make([]byte, signatureStart+SIGNATURE_BYTE_LENGTH)
copy(data[:signatureStart], msg)
// add public key and signature
copy(data[signatureStart:signatureStart+ed25519.PublicKeySize], id.PublicKey)
copy(data[signatureStart+ed25519.PublicKeySize:], signature)
return data
}
// Verifies whether the data contains a valid signature of the message.
func (id *Identity) VerifySignature(data []byte) error {
signatureStart := len(data) - SIGNATURE_BYTE_LENGTH
if signatureStart <= 0 {
return ErrInvalidDataLen
}
msg := data[:signatureStart]
// ignore the public key
sig := data[signatureStart+ed25519.PublicKeySize:]
if !ed25519.Verify(id.PublicKey, msg, sig) {
return ErrInvalidSignature
}
return nil
}
// Returns the identitiy derived from the signed message.
func FromSignedData(data []byte) (*Identity, error) {
signatureStart := len(data) - SIGNATURE_BYTE_LENGTH
if signatureStart <= 0 {
return nil, ErrInvalidDataLen
}
pubKey := data[signatureStart : signatureStart+ed25519.PublicKeySize]
identity := NewPublicIdentity(pubKey)
if err := identity.VerifySignature(data); err != nil {
return nil, err
}
return identity, nil
}
func (id *Identity) Marshal() []byte {
data := make([]byte, MARSHALED_IDENTITY_TOTAL_SIZE)
copy(data[MARSHALED_IDENTITY_PUBLIC_KEY_START:MARSHALED_IDENTITY_PUBLIC_KEY_END], id.PublicKey)
copy(data[MARSHALED_IDENTITY_PRIVATE_KEY_START:MARSHALED_IDENTITY_PRIVATE_KEY_END], id.privateKey)
return data
}
func Unmarshal(data []byte) (*Identity, error) {
if len(data) != MARSHALED_IDENTITY_TOTAL_SIZE {
return nil, ErrInvalidDataLen
}
publicKey := data[MARSHALED_IDENTITY_PUBLIC_KEY_START:MARSHALED_IDENTITY_PUBLIC_KEY_END]
privateKey := data[MARSHALED_IDENTITY_PRIVATE_KEY_START:MARSHALED_IDENTITY_PRIVATE_KEY_END]
return newPrivateIdentity(publicKey, privateKey), nil
}
func newPrivateIdentity(publicKey []byte, privateKey []byte) *Identity {
identity := NewPublicIdentity(publicKey)
identity.privateKey = privateKey
return identity
}