#ifndef POLY_H
#define POLY_H

#include <stddef.h>
#include <stdint.h>

#include "params.h"

typedef struct {
    uint32_t coeffs[N];
} poly;

void poly_reduce(poly *a);
void poly_csubq(poly *a);
void poly_freeze(poly *a);

void poly_add(
    poly *c, const poly *a, const poly *b);
void poly_sub(
    poly *c, const poly *a, const poly *b);
void poly_shiftl(poly *a);

void poly_ntt(poly *a);
void poly_invntt_montgomery(poly *a);
void poly_pointwise_invmontgomery(
    poly *c, const poly *a, const poly *b);

void poly_power2round(
    poly *a1, poly *a0, const poly *a);
void poly_decompose(
    poly *a1, poly *a0, const poly *a);
uint32_t poly_make_hint(
    poly *h, const poly *a0, const poly *a1);
void poly_use_hint(
    poly *a, const poly *b, const poly *h);

int  poly_chknorm(
    const poly *a, uint32_t B);
void poly_uniform(
    poly *a,
    const uint8_t *seed,
    uint16_t nonce);
void poly_uniform_eta(
    poly *a,
    const uint8_t *seed,
    uint16_t nonce);
void poly_uniform_gamma1m1(
    poly *a,
    const uint8_t seed[CRHBYTES],
    uint16_t nonce);

void polyeta_pack(uint8_t *r, const poly *a);
void polyeta_unpack(poly *r, const uint8_t *a);

void polyt1_pack(uint8_t *r, const poly *a);
void polyt1_unpack(poly *r, const uint8_t *a);

void polyt0_pack(uint8_t *r, const poly *a);
void polyt0_unpack(poly *r, const uint8_t *a);

void polyz_pack(uint8_t *r, const poly *a);
void polyz_unpack(poly *r, const uint8_t *a);

void polyw1_pack(uint8_t *r, const poly *a);

#endif
