main
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}