go.dedis.ch/onet/v4@v4.0.0-pre1/network/encoding.go (about) 1 package network 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "reflect" 8 "sync" 9 10 "go.dedis.ch/kyber/v4/pairing/bn256" 11 "go.dedis.ch/kyber/v4/suites" 12 "golang.org/x/xerrors" 13 14 "go.dedis.ch/kyber/v4" 15 "go.dedis.ch/onet/v4/log" 16 "go.dedis.ch/protobuf" 17 uuid "gopkg.in/satori/go.uuid.v1" 18 ) 19 20 func init() { 21 protobuf.RegisterInterface(func() interface{} { return bn256.NewSuiteG1().Point() }) 22 protobuf.RegisterInterface(func() interface{} { return bn256.NewSuiteG1().Scalar() }) 23 protobuf.RegisterInterface(func() interface{} { return bn256.NewSuiteG2().Point() }) 24 protobuf.RegisterInterface(func() interface{} { return bn256.NewSuiteG2().Scalar() }) 25 protobuf.RegisterInterface(func() interface{} { return bn256.NewSuiteGT().Point() }) 26 protobuf.RegisterInterface(func() interface{} { return bn256.NewSuiteGT().Scalar() }) 27 28 ed25519 := suites.MustFind("Ed25519") 29 protobuf.RegisterInterface(func() interface{} { return ed25519.Point() }) 30 protobuf.RegisterInterface(func() interface{} { return ed25519.Scalar() }) 31 } 32 33 /// Encoding part /// 34 35 // Suite functionalities used globally by the network library. 36 type Suite interface { 37 kyber.Group 38 kyber.Random 39 } 40 41 // Message is a type for any message that the user wants to send 42 type Message interface{} 43 44 // MessageTypeID is the ID used to uniquely identify different registered messages 45 type MessageTypeID uuid.UUID 46 47 // ErrorType is reserved by the network library. When you receive a message of 48 // ErrorType, it is generally because an error happened, then you can call 49 // Error() on it. 50 var ErrorType = MessageTypeID(uuid.Nil) 51 52 // String returns the name of the structure if it is known, else it returns 53 // the hexadecimal value of the Id. 54 func (mId MessageTypeID) String() string { 55 t, ok := registry.get(mId) 56 if ok { 57 return fmt.Sprintf("PTID(%s:%x)", t.String(), uuid.UUID(mId).Bytes()) 58 } 59 return uuid.UUID(mId).String() 60 } 61 62 // Equal returns true if and only if mID2 equals this MessageTypeID 63 func (mId MessageTypeID) Equal(mID2 MessageTypeID) bool { 64 return uuid.Equal(uuid.UUID(mId), uuid.UUID(mID2)) 65 } 66 67 // IsNil returns true iff the MessageTypeID is Nil 68 func (mId MessageTypeID) IsNil() bool { 69 return mId.Equal(MessageTypeID(uuid.Nil)) 70 } 71 72 // NamespaceURL is the basic namespace used for uuid 73 // XXX should move that to external of the library as not every 74 // cothority/packages should be expected to use that. 75 const NamespaceURL = "https://dedis.epfl.ch/" 76 77 // NamespaceBodyType is the namespace used for PacketTypeID 78 const NamespaceBodyType = NamespaceURL + "/protocolType/" 79 80 var globalOrder = binary.BigEndian 81 82 // RegisterMessage registers any struct or ptr and returns the 83 // corresponding MessageTypeID. Once a struct is registered, it can be sent and 84 // received by the network library. 85 func RegisterMessage(msg Message) MessageTypeID { 86 msgType := computeMessageType(msg) 87 val := reflect.ValueOf(msg) 88 if val.Kind() == reflect.Ptr { 89 val = val.Elem() 90 } 91 t := val.Type() 92 registry.put(msgType, t) 93 return msgType 94 } 95 96 // RegisterMessages is a convenience function to register multiple messages 97 // together. It returns the MessageTypeIDs of the registered messages. If you 98 // give the same message more than once, it will register it only once, but return 99 // it's id as many times as it appears in the arguments. 100 func RegisterMessages(msg ...Message) []MessageTypeID { 101 var ret []MessageTypeID 102 for _, m := range msg { 103 ret = append(ret, RegisterMessage(m)) 104 } 105 return ret 106 } 107 108 func computeMessageType(msg Message) MessageTypeID { 109 val := reflect.ValueOf(msg) 110 if val.Kind() == reflect.Ptr { 111 val = val.Elem() 112 } 113 url := NamespaceBodyType + val.Type().String() 114 u := uuid.NewV5(uuid.NamespaceURL, url) 115 return MessageTypeID(u) 116 } 117 118 // MessageType returns a Message's MessageTypeID if registered or ErrorType if 119 // the message has not been registered with RegisterMessage(). 120 func MessageType(msg Message) MessageTypeID { 121 msgType := computeMessageType(msg) 122 _, ok := registry.get(msgType) 123 if !ok { 124 return ErrorType 125 } 126 return msgType 127 } 128 129 // Marshal outputs the type and the byte representation of a structure. It 130 // first marshals the type as a uuid, i.e. a 16 byte length slice, then the 131 // struct encoded by protobuf. That slice of bytes can be then decoded with 132 // Unmarshal. msg must be a pointer to the message. 133 func Marshal(msg Message) ([]byte, error) { 134 var msgType MessageTypeID 135 if msgType = MessageType(msg); msgType == ErrorType { 136 return nil, xerrors.Errorf("type of message %s not registered to the network library", reflect.TypeOf(msg)) 137 } 138 b := new(bytes.Buffer) 139 if err := binary.Write(b, globalOrder, msgType); err != nil { 140 return nil, xerrors.Errorf("buffer write: %v", err) 141 } 142 var buf []byte 143 var err error 144 if buf, err = protobuf.Encode(msg); err != nil { 145 log.Errorf("Error for protobuf encoding: %s %+v", msg, err) 146 if log.DebugVisible() > 0 { 147 log.Error(log.Stack()) 148 } 149 return nil, xerrors.Errorf("encoding: %v", err) 150 } 151 _, err = b.Write(buf) 152 if err != nil { 153 return nil, xerrors.Errorf("buffer write: %v", err) 154 } 155 return b.Bytes(), nil 156 } 157 158 // Unmarshal returns the type and the message out of a buffer. One can cast the 159 // resulting Message to a *pointer* of the underlying type, i.e. it returns a 160 // pointer. The type must be registered to the network library in order to be 161 // decodable and the buffer must have been generated by Marshal otherwise it 162 // returns an error. 163 func Unmarshal(buf []byte, suite Suite) (MessageTypeID, Message, error) { 164 b := bytes.NewBuffer(buf) 165 var tID MessageTypeID 166 if err := binary.Read(b, globalOrder, &tID); err != nil { 167 return ErrorType, nil, xerrors.Errorf("buffer read: %v", err) 168 } 169 typ, ok := registry.get(tID) 170 if !ok { 171 return ErrorType, nil, xerrors.Errorf("type %s not registered", tID.String()) 172 } 173 ptrVal := reflect.New(typ) 174 ptr := ptrVal.Interface() 175 constructors := DefaultConstructors(suite) 176 if err := protobuf.DecodeWithConstructors(b.Bytes(), ptr, constructors); err != nil { 177 return ErrorType, nil, xerrors.Errorf("decoding: %v", err) 178 } 179 return tID, ptrVal.Interface(), nil 180 } 181 182 // DumpTypes is used for debugging - it prints out all known types 183 func DumpTypes() { 184 for t, m := range registry.types { 185 log.Print("Type", t, "has message", m) 186 } 187 } 188 189 // DefaultConstructors gives a default constructor for protobuf out of the global suite 190 func DefaultConstructors(suite Suite) protobuf.Constructors { 191 constructors := make(protobuf.Constructors) 192 if suite != nil { 193 var point kyber.Point 194 var secret kyber.Scalar 195 constructors[reflect.TypeOf(&point).Elem()] = func() interface{} { return suite.Point() } 196 constructors[reflect.TypeOf(&secret).Elem()] = func() interface{} { return suite.Scalar() } 197 } 198 return constructors 199 } 200 201 var registry = newTypeRegistry() 202 203 type typeRegistry struct { 204 types map[MessageTypeID]reflect.Type 205 lock sync.Mutex 206 } 207 208 func newTypeRegistry() *typeRegistry { 209 return &typeRegistry{ 210 types: make(map[MessageTypeID]reflect.Type), 211 lock: sync.Mutex{}, 212 } 213 } 214 215 // get returns the reflect.Type corresponding to the registered PacketTypeID 216 // an a boolean indicating if the type is actually registered or not. 217 func (tr *typeRegistry) get(mid MessageTypeID) (reflect.Type, bool) { 218 tr.lock.Lock() 219 defer tr.lock.Unlock() 220 t, ok := tr.types[mid] 221 return t, ok 222 } 223 224 // put stores the given type in the typeRegistry. 225 func (tr *typeRegistry) put(mid MessageTypeID, typ reflect.Type) { 226 tr.lock.Lock() 227 defer tr.lock.Unlock() 228 tr.types[mid] = typ 229 }