// SPDX-License-Identifier: BSD-3-Clause
//
// Generated from CryptoGAMS poly1305-armv4.pl by plan9-xlate.pl. The
// generated poly1305_arm.s carries the upstream BSD-3-Clause notice
// in its file header.

//go:build arm

//go:generate sh ../regen/regen.sh

// Package poly1305 implements Poly1305 with the CryptoGAMS ARMv4
// assembly inner loop, regenerated by tsasm/arm/regen/plan9-xlate.pl.
// It only builds on GOARCH=arm; other architectures should use
// golang.org/x/crypto/poly1305.
package poly1305

import "unsafe"

const (
	KeySize = 32
	TagSize = 16
)

// ctxSize is the byte size of the upstream poly1305 state struct.
// Scalar paths use the first 40 bytes (5 base-2^32 h limbs at 0..19,
// 4 r limbs at 20..35, an is_base2_26 flag at 36). The NEON paths
// use more; we size generously.
const ctxSize = 192

//go:noescape
func poly1305_init(ctx unsafe.Pointer, key unsafe.Pointer)

//go:noescape
func poly1305_blocks(ctx unsafe.Pointer, inp unsafe.Pointer, length uintptr, padbit uintptr)

//go:noescape
func poly1305_emit(ctx unsafe.Pointer, mac unsafe.Pointer, nonce unsafe.Pointer)

// Sum computes a Poly1305 MAC of m under key, writing the 16-byte tag
// to out.
func Sum(out *[TagSize]byte, m []byte, key *[KeySize]byte) {
	var mac MAC
	mac.Init(key)
	mac.Write(m)
	mac.Sum(out)
}

// MAC is an incremental Poly1305 message-authentication code computer.
// Single-use; not safe for concurrent use. Zero-value is not usable --
// call Init first.
type MAC struct {
	ctx   [ctxSize]byte
	nonce [16]byte
	buf   [16]byte
	n     int
}

// New returns a fresh MAC keyed with key. Prefer (*MAC).Init for hot
// paths; this constructor heap-allocates.
func New(key *[KeySize]byte) *MAC {
	m := new(MAC)
	m.Init(key)
	return m
}

// Init keys an existing (typically stack-allocated) MAC with key.
func (m *MAC) Init(key *[KeySize]byte) {
	*m = MAC{}
	poly1305_init(unsafe.Pointer(&m.ctx[0]), unsafe.Pointer(&key[0]))
	copy(m.nonce[:], key[16:])
}

// Write feeds bytes into the MAC. Returns len(p), nil.
func (m *MAC) Write(p []byte) (int, error) {
	n := len(p)
	if m.n > 0 {
		k := copy(m.buf[m.n:], p)
		m.n += k
		p = p[k:]
		if m.n < 16 {
			return n, nil
		}
		poly1305_blocks(unsafe.Pointer(&m.ctx[0]), unsafe.Pointer(&m.buf[0]), 16, 1)
		m.n = 0
	}
	if blocks := len(p) >> 4; blocks > 0 {
		poly1305_blocks(unsafe.Pointer(&m.ctx[0]), unsafe.Pointer(&p[0]), uintptr(blocks*16), 1)
		p = p[blocks*16:]
	}
	if len(p) > 0 {
		copy(m.buf[:], p)
		m.n = len(p)
	}
	return n, nil
}

// Sum finalizes the MAC and writes the 16-byte tag to out.
func (m *MAC) Sum(out *[TagSize]byte) {
	if m.n > 0 {
		var pad [16]byte
		copy(pad[:], m.buf[:m.n])
		pad[m.n] = 1
		poly1305_blocks(unsafe.Pointer(&m.ctx[0]), unsafe.Pointer(&pad[0]), 16, 0)
		m.n = 0
	}
	poly1305_emit(unsafe.Pointer(&m.ctx[0]), unsafe.Pointer(&out[0]), unsafe.Pointer(&m.nonce[0]))
}
