summaryrefslogtreecommitdiffstats
path: root/vendor/go.mau.fi/libsignal/state/record
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.mau.fi/libsignal/state/record')
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/ChainState.go157
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/Doc.go3
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/PendingKeyExchangeState.go91
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/PendingPreKeyState.go62
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/PreKeyRecord.go90
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/SessionRecord.go197
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/SessionState.go531
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/SignedPreKeyRecord.go112
-rw-r--r--vendor/go.mau.fi/libsignal/state/record/UnacknowledgedPreKey.go69
9 files changed, 1312 insertions, 0 deletions
diff --git a/vendor/go.mau.fi/libsignal/state/record/ChainState.go b/vendor/go.mau.fi/libsignal/state/record/ChainState.go
new file mode 100644
index 00000000..dd07bf89
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/ChainState.go
@@ -0,0 +1,157 @@
+package record
+
+import (
+ "go.mau.fi/libsignal/ecc"
+ "go.mau.fi/libsignal/kdf"
+ "go.mau.fi/libsignal/keys/chain"
+ "go.mau.fi/libsignal/keys/message"
+ "go.mau.fi/libsignal/util/bytehelper"
+)
+
+// NewReceiverChainPair will return a new ReceiverChainPair object.
+func NewReceiverChainPair(receiverChain *Chain, index int) *ReceiverChainPair {
+ return &ReceiverChainPair{
+ ReceiverChain: receiverChain,
+ Index: index,
+ }
+}
+
+// ReceiverChainPair is a structure for a receiver chain key and index number.
+type ReceiverChainPair struct {
+ ReceiverChain *Chain
+ Index int
+}
+
+// NewChain returns a new Chain structure for SessionState.
+func NewChain(senderRatchetKeyPair *ecc.ECKeyPair, chainKey *chain.Key,
+ messageKeys []*message.Keys) *Chain {
+
+ return &Chain{
+ senderRatchetKeyPair: senderRatchetKeyPair,
+ chainKey: chainKey,
+ messageKeys: messageKeys,
+ }
+}
+
+// NewChainFromStructure will return a new Chain with the given
+// chain structure.
+func NewChainFromStructure(structure *ChainStructure) (*Chain, error) {
+ // Alias to SliceToArray
+ getArray := bytehelper.SliceToArray
+
+ // Build the sender ratchet key from bytes.
+ senderRatchetKeyPublic, err := ecc.DecodePoint(structure.SenderRatchetKeyPublic, 0)
+ if err != nil {
+ return nil, err
+ }
+ var senderRatchetKeyPrivate ecc.ECPrivateKeyable
+ if len(structure.SenderRatchetKeyPrivate) == 32 {
+ senderRatchetKeyPrivate = ecc.NewDjbECPrivateKey(getArray(structure.SenderRatchetKeyPrivate))
+ }
+ senderRatchetKeyPair := ecc.NewECKeyPair(senderRatchetKeyPublic, senderRatchetKeyPrivate)
+
+ // Build our message keys from the message key structures.
+ messageKeys := make([]*message.Keys, len(structure.MessageKeys))
+ for i := range structure.MessageKeys {
+ messageKeys[i] = message.NewKeysFromStruct(structure.MessageKeys[i])
+ }
+
+ // Build our new chain state.
+ chainState := NewChain(
+ senderRatchetKeyPair,
+ chain.NewKeyFromStruct(structure.ChainKey, kdf.DeriveSecrets),
+ messageKeys,
+ )
+
+ return chainState, nil
+}
+
+// ChainStructure is a serializeable structure for chain states.
+type ChainStructure struct {
+ SenderRatchetKeyPublic []byte
+ SenderRatchetKeyPrivate []byte
+ ChainKey *chain.KeyStructure
+ MessageKeys []*message.KeysStructure
+}
+
+// Chain is a structure used inside the SessionState that keeps
+// track of an ongoing ratcheting chain for a session.
+type Chain struct {
+ senderRatchetKeyPair *ecc.ECKeyPair
+ chainKey *chain.Key
+ messageKeys []*message.Keys
+}
+
+// SenderRatchetKey returns the sender's EC keypair.
+func (c *Chain) SenderRatchetKey() *ecc.ECKeyPair {
+ return c.senderRatchetKeyPair
+}
+
+// SetSenderRatchetKey will set the chain state with the given EC
+// key pair.
+func (c *Chain) SetSenderRatchetKey(key *ecc.ECKeyPair) {
+ c.senderRatchetKeyPair = key
+}
+
+// ChainKey will return the chain key in the chain state.
+func (c *Chain) ChainKey() *chain.Key {
+ return c.chainKey
+}
+
+// SetChainKey will set the chain state's chain key.
+func (c *Chain) SetChainKey(key *chain.Key) {
+ c.chainKey = key
+}
+
+// MessageKeys will return the message keys associated with the
+// chain state.
+func (c *Chain) MessageKeys() []*message.Keys {
+ return c.messageKeys
+}
+
+// SetMessageKeys will set the chain state with the given message
+// keys.
+func (c *Chain) SetMessageKeys(keys []*message.Keys) {
+ c.messageKeys = keys
+}
+
+// AddMessageKeys will append the chain state with the given
+// message keys.
+func (c *Chain) AddMessageKeys(keys *message.Keys) {
+ c.messageKeys = append(c.messageKeys, keys)
+}
+
+// PopFirstMessageKeys will remove the first message key from
+// the chain's list of message keys.
+func (c *Chain) PopFirstMessageKeys() *message.Keys {
+ removed := c.messageKeys[0]
+ c.messageKeys = c.messageKeys[1:]
+
+ return removed
+}
+
+// structure returns a serializeable structure of the chain state.
+func (c *Chain) structure() *ChainStructure {
+ // Alias to ArrayToSlice
+ getSlice := bytehelper.ArrayToSlice
+
+ // Convert our message keys into a serializeable structure.
+ messageKeys := make([]*message.KeysStructure, len(c.messageKeys))
+ for i := range c.messageKeys {
+ messageKeys[i] = message.NewStructFromKeys(c.messageKeys[i])
+ }
+
+ // Convert our sender ratchet key private
+ var senderRatchetKeyPrivate []byte
+ if c.senderRatchetKeyPair.PrivateKey() != nil {
+ senderRatchetKeyPrivate = getSlice(c.senderRatchetKeyPair.PrivateKey().Serialize())
+ }
+
+ // Build the chain structure.
+ return &ChainStructure{
+ SenderRatchetKeyPublic: c.senderRatchetKeyPair.PublicKey().Serialize(),
+ SenderRatchetKeyPrivate: senderRatchetKeyPrivate,
+ ChainKey: chain.NewStructFromKey(c.chainKey),
+ MessageKeys: messageKeys,
+ }
+}
diff --git a/vendor/go.mau.fi/libsignal/state/record/Doc.go b/vendor/go.mau.fi/libsignal/state/record/Doc.go
new file mode 100644
index 00000000..036419da
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/Doc.go
@@ -0,0 +1,3 @@
+// Package record provides the state and record of an ongoing double
+// ratchet session.
+package record
diff --git a/vendor/go.mau.fi/libsignal/state/record/PendingKeyExchangeState.go b/vendor/go.mau.fi/libsignal/state/record/PendingKeyExchangeState.go
new file mode 100644
index 00000000..ac647215
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/PendingKeyExchangeState.go
@@ -0,0 +1,91 @@
+package record
+
+import (
+ "go.mau.fi/libsignal/ecc"
+ "go.mau.fi/libsignal/keys/identity"
+ "go.mau.fi/libsignal/util/bytehelper"
+)
+
+// NewPendingKeyExchange will return a new PendingKeyExchange object.
+func NewPendingKeyExchange(sequence uint32, localBaseKeyPair, localRatchetKeyPair *ecc.ECKeyPair,
+ localIdentityKeyPair *identity.KeyPair) *PendingKeyExchange {
+
+ return &PendingKeyExchange{
+ sequence: sequence,
+ localBaseKeyPair: localBaseKeyPair,
+ localRatchetKeyPair: localRatchetKeyPair,
+ localIdentityKeyPair: localIdentityKeyPair,
+ }
+}
+
+// NewPendingKeyExchangeFromStruct will return a PendingKeyExchange object from
+// the given structure. This is used to get a deserialized pending prekey exchange
+// fetched from persistent storage.
+func NewPendingKeyExchangeFromStruct(structure *PendingKeyExchangeStructure) *PendingKeyExchange {
+ // Return nil if no structure was provided.
+ if structure == nil {
+ return nil
+ }
+
+ // Alias the SliceToArray method.
+ getArray := bytehelper.SliceToArray
+
+ // Convert the bytes in the given structure to ECC objects.
+ localBaseKeyPair := ecc.NewECKeyPair(
+ ecc.NewDjbECPublicKey(getArray(structure.LocalBaseKeyPublic)),
+ ecc.NewDjbECPrivateKey(getArray(structure.LocalBaseKeyPrivate)),
+ )
+ localRatchetKeyPair := ecc.NewECKeyPair(
+ ecc.NewDjbECPublicKey(getArray(structure.LocalRatchetKeyPublic)),
+ ecc.NewDjbECPrivateKey(getArray(structure.LocalRatchetKeyPrivate)),
+ )
+ localIdentityKeyPair := identity.NewKeyPair(
+ identity.NewKey(ecc.NewDjbECPublicKey(getArray(structure.LocalIdentityKeyPublic))),
+ ecc.NewDjbECPrivateKey(getArray(structure.LocalIdentityKeyPrivate)),
+ )
+
+ // Return the PendingKeyExchange with the deserialized keys.
+ return &PendingKeyExchange{
+ sequence: structure.Sequence,
+ localBaseKeyPair: localBaseKeyPair,
+ localRatchetKeyPair: localRatchetKeyPair,
+ localIdentityKeyPair: localIdentityKeyPair,
+ }
+}
+
+// PendingKeyExchangeStructure is a serializable structure for pending
+// key exchanges. This structure is used for persistent storage of the
+// key exchange state.
+type PendingKeyExchangeStructure struct {
+ Sequence uint32
+ LocalBaseKeyPublic []byte
+ LocalBaseKeyPrivate []byte
+ LocalRatchetKeyPublic []byte
+ LocalRatchetKeyPrivate []byte
+ LocalIdentityKeyPublic []byte
+ LocalIdentityKeyPrivate []byte
+}
+
+// PendingKeyExchange is a structure for storing a pending
+// key exchange for a session state.
+type PendingKeyExchange struct {
+ sequence uint32
+ localBaseKeyPair *ecc.ECKeyPair
+ localRatchetKeyPair *ecc.ECKeyPair
+ localIdentityKeyPair *identity.KeyPair
+}
+
+// structre will return a serializable structure of a pending key exchange
+// so it can be persistently stored.
+func (p *PendingKeyExchange) structure() *PendingKeyExchangeStructure {
+ getSlice := bytehelper.ArrayToSlice
+ return &PendingKeyExchangeStructure{
+ Sequence: p.sequence,
+ LocalBaseKeyPublic: getSlice(p.localBaseKeyPair.PublicKey().PublicKey()),
+ LocalBaseKeyPrivate: getSlice(p.localBaseKeyPair.PrivateKey().Serialize()),
+ LocalRatchetKeyPublic: getSlice(p.localRatchetKeyPair.PublicKey().PublicKey()),
+ LocalRatchetKeyPrivate: getSlice(p.localRatchetKeyPair.PrivateKey().Serialize()),
+ LocalIdentityKeyPublic: getSlice(p.localIdentityKeyPair.PublicKey().PublicKey().PublicKey()),
+ LocalIdentityKeyPrivate: getSlice(p.localIdentityKeyPair.PrivateKey().Serialize()),
+ }
+}
diff --git a/vendor/go.mau.fi/libsignal/state/record/PendingPreKeyState.go b/vendor/go.mau.fi/libsignal/state/record/PendingPreKeyState.go
new file mode 100644
index 00000000..27a8878b
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/PendingPreKeyState.go
@@ -0,0 +1,62 @@
+package record
+
+import (
+ "go.mau.fi/libsignal/ecc"
+ "go.mau.fi/libsignal/util/optional"
+)
+
+// NewPendingPreKey will return a new pending pre key object.
+func NewPendingPreKey(preKeyID *optional.Uint32, signedPreKeyID uint32,
+ baseKey ecc.ECPublicKeyable) *PendingPreKey {
+
+ return &PendingPreKey{
+ preKeyID: preKeyID,
+ signedPreKeyID: signedPreKeyID,
+ baseKey: baseKey,
+ }
+}
+
+// NewPendingPreKeyFromStruct will return a new pending prekey object from the
+// given structure.
+func NewPendingPreKeyFromStruct(preKey *PendingPreKeyStructure) (*PendingPreKey, error) {
+ baseKey, err := ecc.DecodePoint(preKey.BaseKey, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ pendingPreKey := NewPendingPreKey(
+ preKey.PreKeyID,
+ preKey.SignedPreKeyID,
+ baseKey,
+ )
+
+ return pendingPreKey, nil
+}
+
+// PendingPreKeyStructure is a serializeable structure for pending
+// prekeys.
+type PendingPreKeyStructure struct {
+ PreKeyID *optional.Uint32
+ SignedPreKeyID uint32
+ BaseKey []byte
+}
+
+// PendingPreKey is a structure for pending pre keys
+// for a session state.
+type PendingPreKey struct {
+ preKeyID *optional.Uint32
+ signedPreKeyID uint32
+ baseKey ecc.ECPublicKeyable
+}
+
+// structure will return a serializeable structure of the pending prekey.
+func (p *PendingPreKey) structure() *PendingPreKeyStructure {
+ if p != nil {
+ return &PendingPreKeyStructure{
+ PreKeyID: p.preKeyID,
+ SignedPreKeyID: p.signedPreKeyID,
+ BaseKey: p.baseKey.Serialize(),
+ }
+ }
+ return nil
+}
diff --git a/vendor/go.mau.fi/libsignal/state/record/PreKeyRecord.go b/vendor/go.mau.fi/libsignal/state/record/PreKeyRecord.go
new file mode 100644
index 00000000..dcd630d2
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/PreKeyRecord.go
@@ -0,0 +1,90 @@
+package record
+
+import (
+ "go.mau.fi/libsignal/ecc"
+ "go.mau.fi/libsignal/util/bytehelper"
+ "go.mau.fi/libsignal/util/optional"
+)
+
+// PreKeySerializer is an interface for serializing and deserializing
+// PreKey objects into bytes. An implementation of this interface should be
+// used to encode/decode the object into JSON, Protobuffers, etc.
+type PreKeySerializer interface {
+ Serialize(preKey *PreKeyStructure) []byte
+ Deserialize(serialized []byte) (*PreKeyStructure, error)
+}
+
+// NewPreKeyFromBytes will return a prekey record from the given bytes using the given serializer.
+func NewPreKeyFromBytes(serialized []byte, serializer PreKeySerializer) (*PreKey, error) {
+ // Use the given serializer to decode the signal message.
+ preKeyStructure, err := serializer.Deserialize(serialized)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewPreKeyFromStruct(preKeyStructure, serializer)
+}
+
+// NewPreKeyFromStruct returns a PreKey record using the given serializable structure.
+func NewPreKeyFromStruct(structure *PreKeyStructure, serializer PreKeySerializer) (*PreKey, error) {
+ // Create the prekey record from the structure.
+ preKey := &PreKey{
+ structure: *structure,
+ serializer: serializer,
+ }
+
+ // Generate the ECC key from bytes.
+ publicKey := ecc.NewDjbECPublicKey(bytehelper.SliceToArray(structure.PublicKey))
+ privateKey := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(structure.PrivateKey))
+ keyPair := ecc.NewECKeyPair(publicKey, privateKey)
+ preKey.keyPair = keyPair
+
+ return preKey, nil
+}
+
+// NewPreKey record returns a new pre key record that can
+// be stored in a PreKeyStore.
+func NewPreKey(id uint32, keyPair *ecc.ECKeyPair, serializer PreKeySerializer) *PreKey {
+ return &PreKey{
+ structure: PreKeyStructure{
+ ID: id,
+ PublicKey: keyPair.PublicKey().Serialize(),
+ PrivateKey: bytehelper.ArrayToSlice(keyPair.PrivateKey().Serialize()),
+ },
+ keyPair: keyPair,
+ serializer: serializer,
+ }
+}
+
+// PreKeyStructure is a structure for serializing PreKey records.
+type PreKeyStructure struct {
+ ID uint32
+ PublicKey []byte
+ PrivateKey []byte
+}
+
+// PreKey record is a structure for storing pre keys inside
+// a PreKeyStore.
+type PreKey struct {
+ structure PreKeyStructure
+ keyPair *ecc.ECKeyPair
+ serializer PreKeySerializer
+}
+
+// ID returns the pre key record's id.
+func (p *PreKey) ID() *optional.Uint32 {
+ // TODO: manually set this to empty if empty
+ return optional.NewOptionalUint32(p.structure.ID)
+}
+
+// KeyPair returns the pre key record's key pair.
+func (p *PreKey) KeyPair() *ecc.ECKeyPair {
+ return p.keyPair
+}
+
+// Serialize uses the PreKey serializer to return the PreKey
+// as serialized bytes.
+func (p *PreKey) Serialize() []byte {
+ structure := p.structure
+ return p.serializer.Serialize(&structure)
+}
diff --git a/vendor/go.mau.fi/libsignal/state/record/SessionRecord.go b/vendor/go.mau.fi/libsignal/state/record/SessionRecord.go
new file mode 100644
index 00000000..01e817e4
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/SessionRecord.go
@@ -0,0 +1,197 @@
+package record
+
+import (
+ "bytes"
+)
+
+// archivedStatesMaxLength describes how many previous session
+// states we should keep track of.
+const archivedStatesMaxLength int = 40
+
+// SessionSerializer is an interface for serializing and deserializing
+// a Signal Session into bytes. An implementation of this interface should be
+// used to encode/decode the object into JSON, Protobuffers, etc.
+type SessionSerializer interface {
+ Serialize(state *SessionStructure) []byte
+ Deserialize(serialized []byte) (*SessionStructure, error)
+}
+
+// NewSessionFromBytes will return a Signal Session from the given
+// bytes using the given serializer.
+func NewSessionFromBytes(serialized []byte, serializer SessionSerializer, stateSerializer StateSerializer) (*Session, error) {
+ // Use the given serializer to decode the session.
+ sessionStructure, err := serializer.Deserialize(serialized)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewSessionFromStructure(sessionStructure, serializer, stateSerializer)
+}
+
+// NewSession creates a new session record and uses the given session and state
+// serializers to convert the object into storeable bytes.
+func NewSession(serializer SessionSerializer, stateSerializer StateSerializer) *Session {
+ record := Session{
+ sessionState: NewState(stateSerializer),
+ previousStates: []*State{},
+ fresh: true,
+ serializer: serializer,
+ }
+
+ return &record
+}
+
+// NewSessionFromStructure will return a new Signal Session from the given
+// session structure and serializer.
+func NewSessionFromStructure(structure *SessionStructure, serializer SessionSerializer,
+ stateSerializer StateSerializer) (*Session, error) {
+
+ // Build our previous states from structure.
+ previousStates := make([]*State, len(structure.PreviousStates))
+ for i := range structure.PreviousStates {
+ var err error
+ previousStates[i], err = NewStateFromStructure(structure.PreviousStates[i], stateSerializer)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Build our current state from structure.
+ sessionState, err := NewStateFromStructure(structure.SessionState, stateSerializer)
+ if err != nil {
+ return nil, err
+ }
+
+ // Build and return our session.
+ session := &Session{
+ previousStates: previousStates,
+ sessionState: sessionState,
+ serializer: serializer,
+ fresh: false,
+ }
+
+ return session, nil
+}
+
+// NewSessionFromState creates a new session record from the given
+// session state.
+func NewSessionFromState(sessionState *State, serializer SessionSerializer) *Session {
+ record := Session{
+ sessionState: sessionState,
+ previousStates: []*State{},
+ fresh: false,
+ serializer: serializer,
+ }
+
+ return &record
+}
+
+// SessionStructure is a public, serializeable structure for Signal
+// Sessions. The states defined in the session are immuteable, as
+// they should not be changed by anyone but the serializer.
+type SessionStructure struct {
+ SessionState *StateStructure
+ PreviousStates []*StateStructure
+}
+
+// Session encapsulates the state of an ongoing session.
+type Session struct {
+ serializer SessionSerializer
+ sessionState *State
+ previousStates []*State
+ fresh bool
+}
+
+// SetState sets the session record's current state to the given
+// one.
+func (r *Session) SetState(sessionState *State) {
+ r.sessionState = sessionState
+}
+
+// IsFresh is used to determine if this is a brand new session
+// or if a session record has already existed.
+func (r *Session) IsFresh() bool {
+ return r.fresh
+}
+
+// SessionState returns the session state object of the current
+// session record.
+func (r *Session) SessionState() *State {
+ return r.sessionState
+}
+
+// PreviousSessionStates returns a list of all currently maintained
+// "previous" session states.
+func (r *Session) PreviousSessionStates() []*State {
+ return r.previousStates
+}
+
+// HasSessionState will check this record to see if the sender's
+// base key exists in the current and previous states.
+func (r *Session) HasSessionState(version int, senderBaseKey []byte) bool {
+ // Ensure the session state version is identical to this one.
+ if r.sessionState.Version() == version && (bytes.Compare(senderBaseKey, r.sessionState.SenderBaseKey()) == 0) {
+ return true
+ }
+
+ // Loop through all of our previous states and see if this
+ // exists in our state.
+ for i := range r.previousStates {
+ if r.previousStates[i].Version() == version && bytes.Compare(senderBaseKey, r.previousStates[i].SenderBaseKey()) == 0 {
+ return true
+ }
+ }
+
+ return false
+}
+
+// ArchiveCurrentState moves the current session state into the list
+// of "previous" session states, and replaces the current session state
+// with a fresh reset instance.
+func (r *Session) ArchiveCurrentState() {
+ r.PromoteState(NewState(r.sessionState.serializer))
+}
+
+// PromoteState takes the given session state and replaces it with the
+// current state, pushing the previous current state to "previousStates".
+func (r *Session) PromoteState(promotedState *State) {
+ r.previousStates = r.prependStates(r.previousStates, r.sessionState)
+ r.sessionState = promotedState
+
+ // Remove the last state if it has reached our maximum length
+ if len(r.previousStates) > archivedStatesMaxLength {
+ r.previousStates = r.removeLastState(r.previousStates)
+ }
+}
+
+// Serialize will return the session as serialized bytes so it can be
+// persistently stored.
+func (r *Session) Serialize() []byte {
+ return r.serializer.Serialize(r.Structure())
+}
+
+// prependStates takes an array/slice of states and prepends it with
+// the given session state.
+func (r *Session) prependStates(states []*State, sessionState *State) []*State {
+ return append([]*State{sessionState}, states...)
+}
+
+// removeLastState takes an array/slice of states and removes the
+// last element from it.
+func (r *Session) removeLastState(states []*State) []*State {
+ return states[:len(states)-1]
+}
+
+// Structure will return a simple serializable session structure
+// from the given structure. This is used for serialization to persistently
+// store a session record.
+func (r *Session) Structure() *SessionStructure {
+ previousStates := make([]*StateStructure, len(r.previousStates))
+ for i := range r.previousStates {
+ previousStates[i] = r.previousStates[i].structure()
+ }
+ return &SessionStructure{
+ SessionState: r.sessionState.structure(),
+ PreviousStates: previousStates,
+ }
+}
diff --git a/vendor/go.mau.fi/libsignal/state/record/SessionState.go b/vendor/go.mau.fi/libsignal/state/record/SessionState.go
new file mode 100644
index 00000000..d0f61d5c
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/SessionState.go
@@ -0,0 +1,531 @@
+package record
+
+import (
+ "go.mau.fi/libsignal/ecc"
+ "go.mau.fi/libsignal/kdf"
+ "go.mau.fi/libsignal/keys/chain"
+ "go.mau.fi/libsignal/keys/identity"
+ "go.mau.fi/libsignal/keys/message"
+ "go.mau.fi/libsignal/keys/root"
+ "go.mau.fi/libsignal/keys/session"
+ "go.mau.fi/libsignal/logger"
+ "go.mau.fi/libsignal/util/errorhelper"
+ "go.mau.fi/libsignal/util/optional"
+)
+
+const maxMessageKeys int = 2000
+const maxReceiverChains int = 5
+
+// StateSerializer is an interface for serializing and deserializing
+// a Signal State into bytes. An implementation of this interface should be
+// used to encode/decode the object into JSON, Protobuffers, etc.
+type StateSerializer interface {
+ Serialize(state *StateStructure) []byte
+ Deserialize(serialized []byte) (*StateStructure, error)
+}
+
+// NewStateFromBytes will return a Signal State from the given
+// bytes using the given serializer.
+func NewStateFromBytes(serialized []byte, serializer StateSerializer) (*State, error) {
+ // Use the given serializer to decode the signal message.
+ stateStructure, err := serializer.Deserialize(serialized)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewStateFromStructure(stateStructure, serializer)
+}
+
+// NewState returns a new session state.
+func NewState(serializer StateSerializer) *State {
+ return &State{serializer: serializer}
+}
+
+// NewStateFromStructure will return a new session state with the
+// given state structure.
+func NewStateFromStructure(structure *StateStructure, serializer StateSerializer) (*State, error) {
+ // Keep a list of errors, so they can be handled once.
+ errors := errorhelper.NewMultiError()
+
+ // Convert our ecc keys from bytes into object form.
+ localIdentityPublic, err := ecc.DecodePoint(structure.LocalIdentityPublic, 0)
+ errors.Add(err)
+ remoteIdentityPublic, err := ecc.DecodePoint(structure.RemoteIdentityPublic, 0)
+ errors.Add(err)
+ senderBaseKey, err := ecc.DecodePoint(structure.SenderBaseKey, 0)
+ errors.Add(err)
+ var pendingPreKey *PendingPreKey
+ if structure.PendingPreKey != nil {
+ pendingPreKey, err = NewPendingPreKeyFromStruct(structure.PendingPreKey)
+ errors.Add(err)
+ }
+ senderChain, err := NewChainFromStructure(structure.SenderChain)
+ errors.Add(err)
+
+ // Build our receiver chains from structure.
+ receiverChains := make([]*Chain, len(structure.ReceiverChains))
+ for i := range structure.ReceiverChains {
+ receiverChains[i], err = NewChainFromStructure(structure.ReceiverChains[i])
+ errors.Add(err)
+ }
+
+ // Handle any errors. The first error will always be returned if there are multiple.
+ if errors.HasErrors() {
+ return nil, errors
+ }
+
+ // Build our state object.
+ state := &State{
+ localIdentityPublic: identity.NewKey(localIdentityPublic),
+ localRegistrationID: structure.LocalRegistrationID,
+ needsRefresh: structure.NeedsRefresh,
+ pendingKeyExchange: NewPendingKeyExchangeFromStruct(structure.PendingKeyExchange),
+ pendingPreKey: pendingPreKey,
+ previousCounter: structure.PreviousCounter,
+ receiverChains: receiverChains,
+ remoteIdentityPublic: identity.NewKey(remoteIdentityPublic),
+ remoteRegistrationID: structure.RemoteRegistrationID,
+ rootKey: root.NewKey(kdf.DeriveSecrets, structure.RootKey),
+ senderBaseKey: senderBaseKey,
+ senderChain: senderChain,
+ serializer: serializer,
+ sessionVersion: structure.SessionVersion,
+ }
+
+ return state, nil
+}
+
+// StateStructure is the structure of a session state. Fields are public
+// to be used for serialization and deserialization.
+type StateStructure struct {
+ LocalIdentityPublic []byte
+ LocalRegistrationID uint32
+ NeedsRefresh bool
+ PendingKeyExchange *PendingKeyExchangeStructure
+ PendingPreKey *PendingPreKeyStructure
+ PreviousCounter uint32
+ ReceiverChains []*ChainStructure
+ RemoteIdentityPublic []byte
+ RemoteRegistrationID uint32
+ RootKey []byte
+ SenderBaseKey []byte
+ SenderChain *ChainStructure
+ SessionVersion int
+}
+
+// State is a session state that contains the structure for
+// all sessions. Session states are contained inside session records.
+// The session state is implemented as a struct rather than protobuffers
+// to allow other serialization methods.
+type State struct {
+ localIdentityPublic *identity.Key
+ localRegistrationID uint32
+ needsRefresh bool
+ pendingKeyExchange *PendingKeyExchange
+ pendingPreKey *PendingPreKey
+ previousCounter uint32
+ receiverChains []*Chain
+ remoteIdentityPublic *identity.Key
+ remoteRegistrationID uint32
+ rootKey *root.Key
+ senderBaseKey ecc.ECPublicKeyable
+ senderChain *Chain
+ serializer StateSerializer
+ sessionVersion int
+}
+
+// SenderBaseKey returns the sender's base key in bytes.
+func (s *State) SenderBaseKey() []byte {
+ if s.senderBaseKey == nil {
+ return nil
+ }
+ return s.senderBaseKey.Serialize()
+}
+
+// SetSenderBaseKey sets the sender's base key with the given bytes.
+func (s *State) SetSenderBaseKey(senderBaseKey []byte) {
+ s.senderBaseKey, _ = ecc.DecodePoint(senderBaseKey, 0)
+}
+
+// Version returns the session's version.
+func (s *State) Version() int {
+ return s.sessionVersion
+}
+
+// SetVersion sets the session state's version number.
+func (s *State) SetVersion(version int) {
+ s.sessionVersion = version
+}
+
+// RemoteIdentityKey returns the identity key of the remote user.
+func (s *State) RemoteIdentityKey() *identity.Key {
+ return s.remoteIdentityPublic
+}
+
+// SetRemoteIdentityKey sets this session's identity key for the remote
+// user.
+func (s *State) SetRemoteIdentityKey(identityKey *identity.Key) {
+ s.remoteIdentityPublic = identityKey
+}
+
+// LocalIdentityKey returns the session's identity key for the local
+// user.
+func (s *State) LocalIdentityKey() *identity.Key {
+ return s.localIdentityPublic
+}
+
+// SetLocalIdentityKey sets the session's identity key for the local
+// user.
+func (s *State) SetLocalIdentityKey(identityKey *identity.Key) {
+ s.localIdentityPublic = identityKey
+}
+
+// PreviousCounter returns the counter of the previous message.
+func (s *State) PreviousCounter() uint32 {
+ return s.previousCounter
+}
+
+// SetPreviousCounter sets the counter for the previous message.
+func (s *State) SetPreviousCounter(previousCounter uint32) {
+ s.previousCounter = previousCounter
+}
+
+// RootKey returns the root key for the session.
+func (s *State) RootKey() session.RootKeyable {
+ return s.rootKey
+}
+
+// SetRootKey sets the root key for the session.
+func (s *State) SetRootKey(rootKey session.RootKeyable) {
+ s.rootKey = rootKey.(*root.Key)
+}
+
+// SenderRatchetKey returns the public ratchet key of the sender.
+func (s *State) SenderRatchetKey() ecc.ECPublicKeyable {
+ return s.senderChain.senderRatchetKeyPair.PublicKey()
+}
+
+// SenderRatchetKeyPair returns the public/private ratchet key pair
+// of the sender.
+func (s *State) SenderRatchetKeyPair() *ecc.ECKeyPair {
+ return s.senderChain.senderRatchetKeyPair
+}
+
+// HasReceiverChain will check to see if the session state has
+// the given ephemeral key.
+func (s *State) HasReceiverChain(senderEphemeral ecc.ECPublicKeyable) bool {
+ return s.receiverChain(senderEphemeral) != nil
+}
+
+// HasSenderChain will check to see if the session state has a
+// sender chain.
+func (s *State) HasSenderChain() bool {
+ return s.senderChain != nil
+}
+
+// receiverChain will loop through the session state's receiver chains
+// and compare the given ephemeral key. If it is found, then the chain
+// and index will be returned as a pair.
+func (s *State) receiverChain(senderEphemeral ecc.ECPublicKeyable) *ReceiverChainPair {
+ receiverChains := s.receiverChains
+
+ for i, receiverChain := range receiverChains {
+ chainSenderRatchetKey, err := ecc.DecodePoint(receiverChain.senderRatchetKeyPair.PublicKey().Serialize(), 0)
+ if err != nil {
+ logger.Error("Error getting receiverchain: ", err)
+ }
+
+ // If the chainSenderRatchetKey equals our senderEphemeral key, return it.
+ if chainSenderRatchetKey.PublicKey() == senderEphemeral.PublicKey() {
+ return NewReceiverChainPair(receiverChain, i)
+ }
+ }
+
+ return nil
+}
+
+// ReceiverChainKey will use the given ephemeral key to generate a new
+// chain key.
+func (s *State) ReceiverChainKey(senderEphemeral ecc.ECPublicKeyable) *chain.Key {
+ receiverChainAndIndex := s.receiverChain(senderEphemeral)
+ receiverChain := receiverChainAndIndex.ReceiverChain
+
+ if receiverChainAndIndex == nil || receiverChain == nil {
+ return nil
+ }
+
+ return chain.NewKey(
+ kdf.DeriveSecrets,
+ receiverChain.chainKey.Key(),
+ receiverChain.chainKey.Index(),
+ )
+}
+
+// AddReceiverChain will add the given ratchet key and chain key to the session
+// state.
+func (s *State) AddReceiverChain(senderRatchetKey ecc.ECPublicKeyable, chainKey session.ChainKeyable) {
+ // Create a keypair structure with our sender ratchet key.
+ senderKey := ecc.NewECKeyPair(senderRatchetKey, nil)
+
+ // Create a Chain state object that will hold our sender key, chain key, and
+ // message keys.
+ chain := NewChain(senderKey, chainKey.(*chain.Key), []*message.Keys{})
+
+ // Add the Chain state to our list of receiver chain states.
+ s.receiverChains = append(s.receiverChains, chain)
+
+ // If our list of receiver chains is too big, delete the oldest entry.
+ if len(s.receiverChains) > maxReceiverChains {
+ i := 0
+ s.receiverChains = append(s.receiverChains[:i], s.receiverChains[i+1:]...)
+ }
+}
+
+// SetSenderChain will set the given ratchet key pair and chain key for this session
+// state.
+func (s *State) SetSenderChain(senderRatchetKeyPair *ecc.ECKeyPair, chainKey session.ChainKeyable) {
+ // Create a Chain state object that will hold our sender key, chain key, and
+ // message keys.
+ chain := NewChain(senderRatchetKeyPair, chainKey.(*chain.Key), []*message.Keys{})
+
+ // Set the sender chain.
+ s.senderChain = chain
+}
+
+// SenderChainKey will return the chain key of the session state.
+func (s *State) SenderChainKey() session.ChainKeyable {
+ chainKey := s.senderChain.chainKey
+ return chain.NewKey(kdf.DeriveSecrets, chainKey.Key(), chainKey.Index())
+}
+
+// SetSenderChainKey will set the chain key in the chain state for this session to
+// the given chain key.
+func (s *State) SetSenderChainKey(nextChainKey session.ChainKeyable) {
+ senderChain := s.senderChain
+ senderChain.SetChainKey(nextChainKey.(*chain.Key))
+}
+
+// HasMessageKeys returns true if we have message keys associated with the given
+// sender key and counter.
+func (s *State) HasMessageKeys(senderEphemeral ecc.ECPublicKeyable, counter uint32) bool {
+ // Get our chain state that has our chain key.
+ chainAndIndex := s.receiverChain(senderEphemeral)
+ receiverChain := chainAndIndex.ReceiverChain
+
+ // If the chain is empty, we don't have any message keys.
+ if receiverChain == nil {
+ return false
+ }
+
+ // Get our message keys from our receiver chain.
+ messageKeyList := receiverChain.MessageKeys()
+
+ // Loop through our message keys and compare its index with the
+ // given counter.
+ for _, messageKey := range messageKeyList {
+ if messageKey.Index() == counter {
+ return true
+ }
+ }
+
+ return false
+}
+
+// RemoveMessageKeys removes the message key with the given sender key and
+// counter. It will return the removed message key.
+func (s *State) RemoveMessageKeys(senderEphemeral ecc.ECPublicKeyable, counter uint32) *message.Keys {
+ // Get our chain state that has our chain key.
+ chainAndIndex := s.receiverChain(senderEphemeral)
+ chainKey := chainAndIndex.ReceiverChain
+
+ // If the chain is empty, we don't have any message keys.
+ if chainKey == nil {
+ return nil
+ }
+
+ // Get our message keys from our receiver chain.
+ messageKeyList := chainKey.MessageKeys()
+
+ // Loop through our message keys and compare its index with the
+ // given counter. When we find a match, remove it from our list.
+ var rmIndex int
+ for i, messageKey := range messageKeyList {
+ if messageKey.Index() == counter {
+ rmIndex = i
+ break
+ }
+ }
+
+ // Retrive the message key
+ messageKey := chainKey.messageKeys[rmIndex]
+
+ // Delete the message key from the given position.
+ chainKey.messageKeys = append(chainKey.messageKeys[:rmIndex], chainKey.messageKeys[rmIndex+1:]...)
+
+ return message.NewKeys(
+ messageKey.CipherKey(),
+ messageKey.MacKey(),
+ messageKey.Iv(),
+ messageKey.Index(),
+ )
+}
+
+// SetMessageKeys will update the chain associated with the given sender key with
+// the given message keys.
+func (s *State) SetMessageKeys(senderEphemeral ecc.ECPublicKeyable, messageKeys *message.Keys) {
+ chainAndIndex := s.receiverChain(senderEphemeral)
+ chainState := chainAndIndex.ReceiverChain
+
+ // Add the message keys to our chain state.
+ chainState.AddMessageKeys(
+ message.NewKeys(
+ messageKeys.CipherKey(),
+ messageKeys.MacKey(),
+ messageKeys.Iv(),
+ messageKeys.Index(),
+ ),
+ )
+
+ if len(chainState.MessageKeys()) > maxMessageKeys {
+ chainState.PopFirstMessageKeys()
+ }
+}
+
+// SetReceiverChainKey sets the session's receiver chain key with the given chain key
+// associated with the given senderEphemeral key.
+func (s *State) SetReceiverChainKey(senderEphemeral ecc.ECPublicKeyable, chainKey session.ChainKeyable) {
+ chainAndIndex := s.receiverChain(senderEphemeral)
+ chainState := chainAndIndex.ReceiverChain
+ chainState.SetChainKey(chainKey.(*chain.Key))
+}
+
+// SetPendingKeyExchange will set the session's pending key exchange state to the given
+// sequence and key pairs.
+func (s *State) SetPendingKeyExchange(sequence uint32, ourBaseKey, ourRatchetKey *ecc.ECKeyPair,
+ ourIdentityKey *identity.KeyPair) {
+
+ s.pendingKeyExchange = NewPendingKeyExchange(
+ sequence,
+ ourBaseKey,
+ ourRatchetKey,
+ ourIdentityKey,
+ )
+}
+
+// PendingKeyExchangeSequence will return the session's pending key exchange sequence
+// number.
+func (s *State) PendingKeyExchangeSequence() uint32 {
+ return s.pendingKeyExchange.sequence
+}
+
+// PendingKeyExchangeBaseKeyPair will return the session's pending key exchange base keypair.
+func (s *State) PendingKeyExchangeBaseKeyPair() *ecc.ECKeyPair {
+ return s.pendingKeyExchange.localBaseKeyPair
+}
+
+// PendingKeyExchangeRatchetKeyPair will return the session's pending key exchange ratchet
+// keypair.
+func (s *State) PendingKeyExchangeRatchetKeyPair() *ecc.ECKeyPair {
+ return s.pendingKeyExchange.localRatchetKeyPair
+}
+
+// PendingKeyExchangeIdentityKeyPair will return the session's pending key exchange identity
+// keypair.
+func (s *State) PendingKeyExchangeIdentityKeyPair() *identity.KeyPair {
+ return s.pendingKeyExchange.localIdentityKeyPair
+}
+
+// HasPendingKeyExchange will return true if there is a valid pending key exchange waiting.
+func (s *State) HasPendingKeyExchange() bool {
+ return s.pendingKeyExchange != nil
+}
+
+// SetUnacknowledgedPreKeyMessage will return unacknowledged pre key message with the
+// given key ids and base key.
+func (s *State) SetUnacknowledgedPreKeyMessage(preKeyID *optional.Uint32, signedPreKeyID uint32, baseKey ecc.ECPublicKeyable) {
+ s.pendingPreKey = NewPendingPreKey(
+ preKeyID,
+ signedPreKeyID,
+ baseKey,
+ )
+}
+
+// HasUnacknowledgedPreKeyMessage will return true if this session has an unacknowledged
+// pre key message.
+func (s *State) HasUnacknowledgedPreKeyMessage() bool {
+ return s.pendingPreKey != nil
+}
+
+// UnackPreKeyMessageItems will return the session's unacknowledged pre key messages.
+func (s *State) UnackPreKeyMessageItems() (*UnackPreKeyMessageItems, error) {
+ preKeyID := s.pendingPreKey.preKeyID
+ signedPreKeyID := s.pendingPreKey.signedPreKeyID
+ baseKey, err := ecc.DecodePoint(s.pendingPreKey.baseKey.Serialize(), 0)
+ if err != nil {
+ return nil, err
+ }
+ return NewUnackPreKeyMessageItems(preKeyID, signedPreKeyID, baseKey), nil
+}
+
+// ClearUnackPreKeyMessage will clear the session's pending pre key.
+func (s *State) ClearUnackPreKeyMessage() {
+ s.pendingPreKey = nil
+}
+
+// SetRemoteRegistrationID sets the remote user's registration id.
+func (s *State) SetRemoteRegistrationID(registrationID uint32) {
+ s.remoteRegistrationID = registrationID
+}
+
+// RemoteRegistrationID returns the remote user's registration id.
+func (s *State) RemoteRegistrationID() uint32 {
+ return s.remoteRegistrationID
+}
+
+// SetLocalRegistrationID sets the local user's registration id.
+func (s *State) SetLocalRegistrationID(registrationID uint32) {
+ s.localRegistrationID = registrationID
+}
+
+// LocalRegistrationID returns the local user's registration id.
+func (s *State) LocalRegistrationID() uint32 {
+ return s.localRegistrationID
+}
+
+// Serialize will return the state as bytes using the given serializer.
+func (s *State) Serialize() []byte {
+ return s.serializer.Serialize(s.structure())
+}
+
+// structure will return a serializable structure of the
+// the given state so it can be persistently stored.
+func (s *State) structure() *StateStructure {
+ // Convert our receiver chains into a serializeable structure
+ receiverChains := make([]*ChainStructure, len(s.receiverChains))
+ for i := range s.receiverChains {
+ receiverChains[i] = s.receiverChains[i].structure()
+ }
+
+ // Convert our pending key exchange into a serializeable structure
+ var pendingKeyExchange *PendingKeyExchangeStructure
+ if s.pendingKeyExchange != nil {
+ pendingKeyExchange = s.pendingKeyExchange.structure()
+ }
+
+ // Build and return our state structure.
+ return &StateStructure{
+ LocalIdentityPublic: s.localIdentityPublic.Serialize(),
+ LocalRegistrationID: s.localRegistrationID,
+ NeedsRefresh: s.needsRefresh,
+ PendingKeyExchange: pendingKeyExchange,
+ PendingPreKey: s.pendingPreKey.structure(),
+ PreviousCounter: s.previousCounter,
+ ReceiverChains: receiverChains,
+ RemoteIdentityPublic: s.remoteIdentityPublic.Serialize(),
+ RemoteRegistrationID: s.remoteRegistrationID,
+ RootKey: s.rootKey.Bytes(),
+ SenderBaseKey: s.senderBaseKey.Serialize(),
+ SenderChain: s.senderChain.structure(),
+ SessionVersion: s.sessionVersion,
+ }
+}
diff --git a/vendor/go.mau.fi/libsignal/state/record/SignedPreKeyRecord.go b/vendor/go.mau.fi/libsignal/state/record/SignedPreKeyRecord.go
new file mode 100644
index 00000000..f11ab088
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/SignedPreKeyRecord.go
@@ -0,0 +1,112 @@
+package record
+
+import (
+ "go.mau.fi/libsignal/ecc"
+ "go.mau.fi/libsignal/util/bytehelper"
+)
+
+// SignedPreKeySerializer is an interface for serializing and deserializing
+// SignedPreKey objects into bytes. An implementation of this interface should be
+// used to encode/decode the object into JSON, Protobuffers, etc.
+type SignedPreKeySerializer interface {
+ Serialize(signedPreKey *SignedPreKeyStructure) []byte
+ Deserialize(serialized []byte) (*SignedPreKeyStructure, error)
+}
+
+// NewSignedPreKeyFromBytes will return a signed prekey record from the given
+// bytes using the given serializer.
+func NewSignedPreKeyFromBytes(serialized []byte, serializer SignedPreKeySerializer) (*SignedPreKey, error) {
+ // Use the given serializer to decode the signal message.
+ signedPreKeyStructure, err := serializer.Deserialize(serialized)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewSignedPreKeyFromStruct(signedPreKeyStructure, serializer)
+}
+
+// NewSignedPreKeyFromStruct returns a SignedPreKey record using the given
+// serializable structure.
+func NewSignedPreKeyFromStruct(structure *SignedPreKeyStructure,
+ serializer SignedPreKeySerializer) (*SignedPreKey, error) {
+
+ // Create the signed prekey record from the structure.
+ signedPreKey := &SignedPreKey{
+ structure: *structure,
+ serializer: serializer,
+ signature: bytehelper.SliceToArray64(structure.Signature),
+ }
+
+ // Generate the ECC key from bytes.
+ publicKey := ecc.NewDjbECPublicKey(bytehelper.SliceToArray(structure.PublicKey))
+ privateKey := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(structure.PrivateKey))
+ keyPair := ecc.NewECKeyPair(publicKey, privateKey)
+ signedPreKey.keyPair = keyPair
+
+ return signedPreKey, nil
+}
+
+// NewSignedPreKey record creates a new signed pre key record
+// with the given properties.
+func NewSignedPreKey(id uint32, timestamp int64, keyPair *ecc.ECKeyPair,
+ sig [64]byte, serializer SignedPreKeySerializer) *SignedPreKey {
+
+ return &SignedPreKey{
+ structure: SignedPreKeyStructure{
+ ID: id,
+ Timestamp: timestamp,
+ PublicKey: keyPair.PublicKey().Serialize(),
+ PrivateKey: bytehelper.ArrayToSlice(keyPair.PrivateKey().Serialize()),
+ Signature: bytehelper.ArrayToSlice64(sig),
+ },
+ keyPair: keyPair,
+ signature: sig,
+ serializer: serializer,
+ }
+}
+
+// SignedPreKeyStructure is a flat structure of a signed pre key, used
+// for serialization and deserialization.
+type SignedPreKeyStructure struct {
+ ID uint32
+ PublicKey []byte
+ PrivateKey []byte
+ Signature []byte
+ Timestamp int64
+}
+
+// SignedPreKey record is a structure for storing a signed
+// pre key in a SignedPreKey store.
+type SignedPreKey struct {
+ structure SignedPreKeyStructure
+ keyPair *ecc.ECKeyPair
+ signature [64]byte
+ serializer SignedPreKeySerializer
+}
+
+// ID returns the record's id.
+func (s *SignedPreKey) ID() uint32 {
+ return s.structure.ID
+}
+
+// Timestamp returns the record's timestamp
+func (s *SignedPreKey) Timestamp() int64 {
+ return s.structure.Timestamp
+}
+
+// KeyPair returns the signed pre key record's key pair.
+func (s *SignedPreKey) KeyPair() *ecc.ECKeyPair {
+ return s.keyPair
+}
+
+// Signature returns the record's signed prekey signature.
+func (s *SignedPreKey) Signature() [64]byte {
+ return s.signature
+}
+
+// Serialize uses the SignedPreKey serializer to return the SignedPreKey
+// as serialized bytes.
+func (s *SignedPreKey) Serialize() []byte {
+ structure := s.structure
+ return s.serializer.Serialize(&structure)
+}
diff --git a/vendor/go.mau.fi/libsignal/state/record/UnacknowledgedPreKey.go b/vendor/go.mau.fi/libsignal/state/record/UnacknowledgedPreKey.go
new file mode 100644
index 00000000..61fe0644
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/state/record/UnacknowledgedPreKey.go
@@ -0,0 +1,69 @@
+package record
+
+import (
+ "go.mau.fi/libsignal/ecc"
+ "go.mau.fi/libsignal/util/optional"
+)
+
+// NewUnackPreKeyMessageItems returns message items that are unacknowledged.
+func NewUnackPreKeyMessageItems(preKeyID *optional.Uint32, signedPreKeyID uint32,
+ baseKey ecc.ECPublicKeyable) *UnackPreKeyMessageItems {
+
+ return &UnackPreKeyMessageItems{
+ preKeyID: preKeyID,
+ signedPreKeyID: signedPreKeyID,
+ baseKey: baseKey,
+ }
+}
+
+// NewUnackPreKeyMessageItemsFromStruct will return a new unacknowledged prekey
+// message items object from the given structure.
+func NewUnackPreKeyMessageItemsFromStruct(structure *UnackPreKeyMessageItemsStructure) *UnackPreKeyMessageItems {
+ baseKey, _ := ecc.DecodePoint(structure.BaseKey, 0)
+ return NewUnackPreKeyMessageItems(
+ structure.PreKeyID,
+ structure.SignedPreKeyID,
+ baseKey,
+ )
+}
+
+// UnackPreKeyMessageItemsStructure is a serializable structure for unackowledged
+// prekey message items.
+type UnackPreKeyMessageItemsStructure struct {
+ PreKeyID *optional.Uint32
+ SignedPreKeyID uint32
+ BaseKey []byte
+}
+
+// UnackPreKeyMessageItems is a structure for messages that have not been
+// acknowledged.
+type UnackPreKeyMessageItems struct {
+ preKeyID *optional.Uint32
+ signedPreKeyID uint32
+ baseKey ecc.ECPublicKeyable
+}
+
+// PreKeyID returns the prekey id of the unacknowledged message.
+func (u *UnackPreKeyMessageItems) PreKeyID() *optional.Uint32 {
+ return u.preKeyID
+}
+
+// SignedPreKeyID returns the signed prekey id of the unacknowledged message.
+func (u *UnackPreKeyMessageItems) SignedPreKeyID() uint32 {
+ return u.signedPreKeyID
+}
+
+// BaseKey returns the ECC public key of the unacknowledged message.
+func (u *UnackPreKeyMessageItems) BaseKey() ecc.ECPublicKeyable {
+ return u.baseKey
+}
+
+// structure will return a serializable base structure
+// for unacknowledged prekey message items.
+func (u *UnackPreKeyMessageItems) structure() *UnackPreKeyMessageItemsStructure {
+ return &UnackPreKeyMessageItemsStructure{
+ PreKeyID: u.preKeyID,
+ SignedPreKeyID: u.signedPreKeyID,
+ BaseKey: u.baseKey.Serialize(),
+ }
+}