encoding.mx raw

   1  // Package mls implements MLS RFC 9420 cipher suite 0x0003.
   2  //
   3  // Wire-width discipline (see CLAUDE.md "Integer widths on the wire"):
   4  // every function here that touches the wire uses explicit-width integer
   5  // types (uint8/uint16/uint32/uint64). Bare int is avoided on all wire
   6  // paths. Varints decode into uint32 — MLS §5.1.3 caps varint values at
   7  // 2^30-1 so uint32 is the exact upper bound, not a best-guess.
   8  package mls
   9  
  10  // MLS wire encoding (RFC 9420 §6).
  11  // Replaces cryptobyte.Builder/String from the Go version with direct
  12  // byte manipulation suitable for Moxie's string=[]byte model.
  13  
  14  import "errors"
  15  
  16  var (
  17  	errUnexpectedEOF = errors.New("mls: unexpected EOF")
  18  	errVarintOverflow = errors.New("mls: varint exceeds 30 bits")
  19  	errExcessBytes = errors.New("mls: excess bytes after unmarshal")
  20  )
  21  
  22  // --- Reader ---
  23  
  24  // Reader consumes bytes sequentially from a buffer.
  25  type Reader struct {
  26  	data []byte
  27  	pos  int
  28  }
  29  
  30  func newReader(data []byte) Reader {
  31  	return Reader{data: data}
  32  }
  33  
  34  func (r *Reader) empty() bool {
  35  	return r.pos >= len(r.data)
  36  }
  37  
  38  func (r *Reader) remaining() int {
  39  	return len(r.data) - r.pos
  40  }
  41  
  42  // readByte reads one byte.
  43  func (r *Reader) readByte() (byte, bool) {
  44  	if r.pos >= len(r.data) {
  45  		return 0, false
  46  	}
  47  	b := r.data[r.pos]
  48  	r.pos++
  49  	return b, true
  50  }
  51  
  52  // readN reads n bytes as a slice of the underlying buffer (no copy).
  53  func (r *Reader) readN(n int) ([]byte, bool) {
  54  	if r.remaining() < n {
  55  		return nil, false
  56  	}
  57  	out := r.data[r.pos : r.pos+n]
  58  	r.pos += n
  59  	return out, true
  60  }
  61  
  62  // readUint16 reads a big-endian uint16.
  63  func (r *Reader) readUint16() (uint16, bool) {
  64  	if r.remaining() < 2 {
  65  		return 0, false
  66  	}
  67  	v := uint16(r.data[r.pos])<<8 | uint16(r.data[r.pos+1])
  68  	r.pos += 2
  69  	return v, true
  70  }
  71  
  72  // readUint32 reads a big-endian uint32.
  73  func (r *Reader) readUint32() (uint32, bool) {
  74  	if r.remaining() < 4 {
  75  		return 0, false
  76  	}
  77  	v := uint32(r.data[r.pos])<<24 | uint32(r.data[r.pos+1])<<16 |
  78  		uint32(r.data[r.pos+2])<<8 | uint32(r.data[r.pos+3])
  79  	r.pos += 4
  80  	return v, true
  81  }
  82  
  83  // readUint64 reads a big-endian uint64.
  84  func (r *Reader) readUint64() (uint64, bool) {
  85  	if r.remaining() < 8 {
  86  		return 0, false
  87  	}
  88  	v := uint64(r.data[r.pos])<<56 | uint64(r.data[r.pos+1])<<48 |
  89  		uint64(r.data[r.pos+2])<<40 | uint64(r.data[r.pos+3])<<32 |
  90  		uint64(r.data[r.pos+4])<<24 | uint64(r.data[r.pos+5])<<16 |
  91  		uint64(r.data[r.pos+6])<<8 | uint64(r.data[r.pos+7])
  92  	r.pos += 8
  93  	return v, true
  94  }
  95  
  96  // readVarint reads a QUIC-style variable-length integer (RFC 9000 §16).
  97  // 2-bit prefix encodes length: 00=1byte/6bits, 01=2bytes/14bits, 10=4bytes/30bits.
  98  // MLS §5.1.3 caps values at 2^30-1, which fits in uint32 exactly — the
  99  // return type is the tight upper bound, not a convenience cast.
 100  func (r *Reader) readVarint() (uint32, bool) {
 101  	b, ok := r.readByte()
 102  	if !ok {
 103  		return 0, false
 104  	}
 105  	prefix := b >> 6
 106  	if prefix == 3 {
 107  		return 0, false
 108  	}
 109  	n := int(1) << uint(prefix) // total bytes: 1, 2, or 4
 110  	v := uint32(b & 0x3F)
 111  	for i := 0; i < n-1; i++ {
 112  		b, ok = r.readByte()
 113  		if !ok {
 114  			return 0, false
 115  		}
 116  		v = (v << 8) | uint32(b)
 117  	}
 118  	// reject non-minimal encodings
 119  	if prefix >= 1 && v < uint32(1)<<uint32(8*(n/2)-2) {
 120  		return 0, false
 121  	}
 122  	return v, true
 123  }
 124  
 125  // readOpaqueVec reads a varint-length-prefixed byte vector (copy).
 126  func (r *Reader) readOpaqueVec() ([]byte, bool) {
 127  	n, ok := r.readVarint()
 128  	if !ok {
 129  		return nil, false
 130  	}
 131  	src, ok := r.readN(int(n))
 132  	if !ok {
 133  		return nil, false
 134  	}
 135  	dst := []byte{:int(n)}
 136  	copy(dst, src)
 137  	return dst, true
 138  }
 139  
 140  // readVector reads a varint-length-prefixed sequence of encoded elements,
 141  // calling f for each element until the sub-buffer is exhausted.
 142  func (r *Reader) readVector(f func(r *Reader) error) error {
 143  	n, ok := r.readVarint()
 144  	if !ok {
 145  		return errUnexpectedEOF
 146  	}
 147  	data, ok := r.readN(int(n))
 148  	if !ok {
 149  		return errUnexpectedEOF
 150  	}
 151  	sub := newReader(data)
 152  	for !sub.empty() {
 153  		if err := f(&sub); err != nil {
 154  			return err
 155  		}
 156  	}
 157  	return nil
 158  }
 159  
 160  // readOptional reads a 1-byte presence flag (0 or 1).
 161  func (r *Reader) readOptional() (bool, bool) {
 162  	b, ok := r.readByte()
 163  	if !ok {
 164  		return false, false
 165  	}
 166  	switch b {
 167  	case 0:
 168  		return false, true
 169  	case 1:
 170  		return true, true
 171  	default:
 172  		return false, false
 173  	}
 174  }
 175  
 176  // --- Writer ---
 177  
 178  // Writer accumulates serialized bytes with deferred error checking.
 179  // Errors are recorded but do not halt writes; check via bytes().
 180  type Writer struct {
 181  	buf []byte
 182  	err error
 183  }
 184  
 185  func (w *Writer) setError(err error) {
 186  	if w.err == nil {
 187  		w.err = err
 188  	}
 189  }
 190  
 191  func (w *Writer) addByte(v byte) {
 192  	if w.err != nil {
 193  		return
 194  	}
 195  	w.buf = append(w.buf, v)
 196  }
 197  
 198  func (w *Writer) addBytes(v []byte) {
 199  	if w.err != nil {
 200  		return
 201  	}
 202  	w.buf = append(w.buf, v...)
 203  }
 204  
 205  func (w *Writer) addUint16(v uint16) {
 206  	if w.err != nil {
 207  		return
 208  	}
 209  	w.buf = append(w.buf, byte(v>>8), byte(v))
 210  }
 211  
 212  func (w *Writer) addUint32(v uint32) {
 213  	if w.err != nil {
 214  		return
 215  	}
 216  	w.buf = append(w.buf, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
 217  }
 218  
 219  func (w *Writer) addUint64(v uint64) {
 220  	if w.err != nil {
 221  		return
 222  	}
 223  	w.buf = append(w.buf, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32),
 224  		byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
 225  }
 226  
 227  // writeVarint encodes a QUIC-style variable-length integer.
 228  // MLS §5.1.3 caps values at 2^30-1; larger values yield errVarintOverflow.
 229  func (w *Writer) writeVarint(n uint32) {
 230  	if w.err != nil {
 231  		return
 232  	}
 233  	switch {
 234  	case n < 1<<6:
 235  		w.buf = append(w.buf, byte(n))
 236  	case n < 1<<14:
 237  		w.buf = append(w.buf, 0x40|byte(n>>8), byte(n))
 238  	case n < 1<<30:
 239  		w.buf = append(w.buf, 0x80|byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
 240  	default:
 241  		w.setError(errVarintOverflow)
 242  	}
 243  }
 244  
 245  // writeOpaqueVec writes a varint-length-prefixed byte vector.
 246  func (w *Writer) writeOpaqueVec(data []byte) {
 247  	if w.err != nil {
 248  		return
 249  	}
 250  	w.writeVarint(uint32(len(data)))
 251  	w.addBytes(data)
 252  }
 253  
 254  // writeVector encodes n elements into a varint-length-prefixed block.
 255  // Each element is written by calling f(child, i).
 256  func (w *Writer) writeVector(n int, f func(w *Writer, i int)) {
 257  	if w.err != nil {
 258  		return
 259  	}
 260  	var child Writer
 261  	for i := 0; i < n; i++ {
 262  		f(&child, i)
 263  		if child.err != nil {
 264  			w.setError(child.err)
 265  			return
 266  		}
 267  	}
 268  	w.writeOpaqueVec(child.buf)
 269  }
 270  
 271  // writeOptional writes a 1-byte presence flag.
 272  func (w *Writer) writeOptional(present bool) {
 273  	if present {
 274  		w.addByte(1)
 275  	} else {
 276  		w.addByte(0)
 277  	}
 278  }
 279  
 280  func (w *Writer) bytes() ([]byte, error) {
 281  	return w.buf, w.err
 282  }
 283  
 284  // --- Marshal / Unmarshal interfaces ---
 285  
 286  type unmarshaler interface {
 287  	unmarshal(r *Reader) error
 288  }
 289  
 290  type marshaler interface {
 291  	marshal(w *Writer)
 292  }
 293  
 294  func unmarshalRaw(raw []byte, v unmarshaler) error {
 295  	r := newReader(raw)
 296  	if err := v.unmarshal(&r); err != nil {
 297  		return err
 298  	}
 299  	if !r.empty() {
 300  		return errExcessBytes
 301  	}
 302  	return nil
 303  }
 304  
 305  func marshalRaw(v marshaler) ([]byte, error) {
 306  	var w Writer
 307  	v.marshal(&w)
 308  	return w.bytes()
 309  }
 310