// Code generated by {{ .Meta.Name }}. Do not edit.

use crate::fields::FieldElement;

/// Exponentiates a field element to a constant power.
///
/// This is used to either exponentiate field elements to the power (|F| - 2), in order to compute
/// multiplicative inverses in constant time, or to the power (p + 1) / 4, in order to compute
/// square roots in certain fields in constant time.
#[allow(unused_mut)]
pub(crate) fn exp<F: FieldElement>(x: F) -> F {
    // This is implemented with addition chain exponentiation, using the following chain:
    //
    {{- range lines (format .Script) }}
    //   {{ . }}
    {{- end }}
    //
    // Operations: {{ .Ops.Doubles }} squares and {{ .Ops.Adds }} multiplications.
    //
    // Generated by {{ .Meta.Module }} {{ .Meta.ReleaseTag }}.
{{ range .Program.Temporaries }}
    let mut {{ . }};
    {{- end }}
    let mut z;
{{ range $i := .Program.Instructions }}
    // {{ printf "Step %d: %s = x^%#x" $i.Output.Index $i.Output (index $.Chain $i.Output.Index) }}

    {{- with add $i.Op -}}
    {{- if eq $i.Output.Identifier .X.Identifier }}
    {{ $i.Output }} *= {{ .Y }};
    {{- else }}
    {{ $i.Output }} = {{ .X }} * {{ .Y }};
    {{- end }}
{{ end -}}

    {{- with double $i.Op }}
    {{ $i.Output }} = {{ .X }}.square();
{{ end -}}

    {{- with shift $i.Op -}}
    {{- $first := 0 -}}
    {{- if ne $i.Output.Identifier .X.Identifier }}
    {{ $i.Output }} = {{ .X }}.square();
    {{- $first = 1 -}}
    {{- end }}
    for _ in {{ $first }}..{{ .S }} {
        {{ $i.Output }} = {{ $i.Output }}.square();
    }
{{ end -}}

    {{- end }}
    z
}
