main
Raw Download raw file
 1// Copyright 2017 The Go Authors. All rights reserved.
 2// Use of this source code is governed by a BSD-style
 3// license that can be found in the LICENSE file.
 4
 5package encoding
 6
 7import (
 8	"io"
 9	"math/big"
10	"math/bits"
11)
12
13// An MPI is used to store the contents of a big integer, along with the bit
14// length that was specified in the original input. This allows the MPI to be
15// reserialized exactly.
16type MPI struct {
17	bytes     []byte
18	bitLength uint16
19}
20
21// NewMPI returns a MPI initialized with bytes.
22func NewMPI(bytes []byte) *MPI {
23	for len(bytes) != 0 && bytes[0] == 0 {
24		bytes = bytes[1:]
25	}
26	if len(bytes) == 0 {
27		bitLength := uint16(0)
28		return &MPI{bytes, bitLength}
29	}
30	bitLength := 8*uint16(len(bytes)-1) + uint16(bits.Len8(bytes[0]))
31	return &MPI{bytes, bitLength}
32}
33
34// Bytes returns the decoded data.
35func (m *MPI) Bytes() []byte {
36	return m.bytes
37}
38
39// BitLength is the size in bits of the decoded data.
40func (m *MPI) BitLength() uint16 {
41	return m.bitLength
42}
43
44// EncodedBytes returns the encoded data.
45func (m *MPI) EncodedBytes() []byte {
46	return append([]byte{byte(m.bitLength >> 8), byte(m.bitLength)}, m.bytes...)
47}
48
49// EncodedLength is the size in bytes of the encoded data.
50func (m *MPI) EncodedLength() uint16 {
51	return uint16(2 + len(m.bytes))
52}
53
54// ReadFrom reads into m the next MPI from r.
55func (m *MPI) ReadFrom(r io.Reader) (int64, error) {
56	var buf [2]byte
57	n, err := io.ReadFull(r, buf[0:])
58	if err != nil {
59		if err == io.EOF {
60			err = io.ErrUnexpectedEOF
61		}
62		return int64(n), err
63	}
64
65	m.bitLength = uint16(buf[0])<<8 | uint16(buf[1])
66	m.bytes = make([]byte, (int(m.bitLength)+7)/8)
67
68	nn, err := io.ReadFull(r, m.bytes)
69	if err == io.EOF {
70		err = io.ErrUnexpectedEOF
71	}
72
73	// remove leading zero bytes from malformed GnuPG encoded MPIs:
74	// https://bugs.gnupg.org/gnupg/issue1853
75	// for _, b := range m.bytes {
76	// 	if b != 0 {
77	// 		break
78	// 	}
79	// 	m.bytes = m.bytes[1:]
80	// 	m.bitLength -= 8
81	// }
82
83	return int64(n) + int64(nn), err
84}
85
86// SetBig initializes m with the bits from n.
87func (m *MPI) SetBig(n *big.Int) *MPI {
88	m.bytes = n.Bytes()
89	m.bitLength = uint16(n.BitLen())
90	return m
91}