1// Copyright 2019 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
5// +build ppc64le,!gccgo,!appengine
6
7package poly1305
8
9//go:noescape
10func initialize(state *[7]uint64, key *[32]byte)
11
12//go:noescape
13func update(state *[7]uint64, msg []byte)
14
15//go:noescape
16func finalize(tag *[TagSize]byte, state *[7]uint64)
17
18// Sum generates an authenticator for m using a one-time key and puts the
19// 16-byte result into out. Authenticating two different messages with the same
20// key allows an attacker to forge messages at will.
21func Sum(out *[16]byte, m []byte, key *[32]byte) {
22	h := newMAC(key)
23	h.Write(m)
24	h.Sum(out)
25}
26
27func newMAC(key *[32]byte) (h mac) {
28	initialize(&h.state, key)
29	return
30}
31
32type mac struct {
33	state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 }
34
35	buffer [TagSize]byte
36	offset int
37}
38
39func (h *mac) Write(p []byte) (n int, err error) {
40	n = len(p)
41	if h.offset > 0 {
42		remaining := TagSize - h.offset
43		if n < remaining {
44			h.offset += copy(h.buffer[h.offset:], p)
45			return n, nil
46		}
47		copy(h.buffer[h.offset:], p[:remaining])
48		p = p[remaining:]
49		h.offset = 0
50		update(&h.state, h.buffer[:])
51	}
52	if nn := len(p) - (len(p) % TagSize); nn > 0 {
53		update(&h.state, p[:nn])
54		p = p[nn:]
55	}
56	if len(p) > 0 {
57		h.offset += copy(h.buffer[h.offset:], p)
58	}
59	return n, nil
60}
61
62func (h *mac) Sum(out *[16]byte) {
63	state := h.state
64	if h.offset > 0 {
65		update(&state, h.buffer[:h.offset])
66	}
67	finalize(out, &state)
68}
69