[[insns-vsha2c, Vector SHA-2 Compression]]
= vsha2c[hl].vv

Synopsis::
Vector SHA-2 two rounds of compression.

Mnemonic::
vsha2ch.vv vd, vs2, vs1 +
vsha2cl.vv vd, vs2, vs1

Encoding (Vector-Vector) High part::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: 'OP-P'},
{bits: 5, name: 'vd'},
{bits: 3, name: 'OPMVV'},
{bits: 5, name: 'vs1'},
{bits: 5, name: 'vs2'},
{bits: 1, name: '1'},
{bits: 6, name: '101110'},
]}
....

Encoding (Vector-Vector) Low part::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: 'OP-P'},
{bits: 5, name: 'vd'},
{bits: 3, name: 'OPMVV'},
{bits: 5, name: 'vs1'},
{bits: 5, name: 'vs2'},
{bits: 1, name: '1'},
{bits: 6, name: '101111'},
]}
....
Reserved Encodings::
* `zvknha`: `SEW` is any value other than 32
* `zvknhb`: `SEW` is any value other than 32 or 64
* The `vd` register group overlaps with either `vs1` or `vs2`

Arguments::

[%autowidth]
[%header,cols="4,2,2,2,2,2"]
|===
|Register
|Direction
|EGW
|EGS
|EEW
|Definition

| Vd  | input  | 4*SEW  | 4 | SEW | current state {c, d, g, h}
| Vs1 | input  | 4*SEW  | 4 | SEW | MessageSched plus constant[3:0]
| Vs2 | input  | 4*SEW  | 4 | SEW | current state {a, b, e, f}
| Vd  | output | 4*SEW  | 4 | SEW | next state {a, b, e, f}
|===

Description::
- `SEW`=32: 2 rounds of SHA-256 compression are performed (`zvknha` and `zvknhb`)
- `SEW`=64: 2 rounds of SHA-512 compression are performed (`zvkhnb`)

Two words of `vs1` are processed with
the 8 words of current state held in `vd` and `vs1` to perform two
rounds of hash computation producing four words of the
next state.


// These instructions take in two SEW words _W1_ and _W0_ which are the next two words of the message
// schedule incremented by the appropriate constant (see
// link:https://doi.org/10.6028/NIST.FIPS.180-4[FIPS PUB 180-4 Secure Hash Standard (SHS)])
// and eight SEW word variables: _a_, _b_, _c_, _d_, _e_, _f_, _g,_ and _h_. The
// output is the new values of _a, b, e_ and _f_ after performing 2 rounds of the hash
// computation. The new values, _c_, _d_, _g_, and _h_, are equal to the input values for _a_, _b_, // _e_, _f_ respectively.

// [TIP]
// .Note to software developers
// ====
// The MessageSchedplus constant input to this instruction is generated by Software
// increment each message schedule word by the corresponding
// round constant as defined in the NIST specification (see <<zvknh>>).
// ====

[TIP]
.Note to software developers
====
The NIST standard (see <<zvknh>>) requires the final hash to be in big-endian byte ordering
within SEW-sized words. Since this instruction treats all words as little-endian,
software needs to perform an endian swap on the final output of this instruction
after all of the message blocks have been processed.
====

[NOTE]
====
The `vsha2ch` version of this instruction uses the two most significant message schedule
words from the element group in `vs1`
while the `vsha2cl` version uses the two least significant message schedule words.
Otherwise, these versions of the instruction are identical.
Having a high and low version of this instruction typically improves performance when 
interleaving independent hashing operations (i.e., when hashing several files at once).
====

// [TIP]
// .Note to software developers
// ====
// These instructions take in two SEW words _W1_ and _W0_ which are the next two words of the message
// schedule incremented by the appropriate constant, 
// and eight SEW word variables: _a_, _b_, _c_, _d_, _e_, _f_, _g,_ and _h_. The
// output is the new values of _a, b, e_ and _f_ after performing 2 rounds of the hash
// computation. The new values, _c_, _d_, _g_, and _h_, are equal to the input values for _a_, _b_, _e_, _f_ respectively.
// ====

// [NOTE]
// ====
// Between executions this instruction it is helpful to swap the register _specifiers_ for
// `vd` and `vs2`. This is because the first instruction's `vd` next state output
// (_a_, _b_, _e_, _f_)
// becomes the second instruction's `vs2` current state input (_a_, _b_, _e_, _f_).
// Likewise the first instruction's `vs2` input (_a_, _b_, _e_, _f_) "ages" to
// becomes the second instruction's `vd` current state input of (_c_, _d_, _g_, _h_).
// ====


[NOTE]
====
Preventing overlap between `vd` and `vs1` or `vs2` simplifies implementation with `VLEN < EGW`.
This restriction does not have any coding impact since proper implementation of the algorithm requires
that `vd`, `vs1` and `vs2` each are different registers.
====



// The number of element groups to be processed is `vl`/`EGS`.
// `vl` must be set to the number of `SEW=32` elements to be processed and
// therefore must be a multiple of `EGS=4`. +
// Likewise, `vstart` must be a multiple of `EGS=4`.

Operation::
[source,sail]
--
function clause execute (VSHA2c(vs2, vs1, vd)) = {
  if(LMUL*VLEN < EGW)  then {
    handle_illegal();  // illegal instruction exception
    RETIRE_FAIL
  } else {

  eg_len = (vl/EGS)
  eg_start = (vstart/EGS)
  
  foreach (i from eg_start to eg_len-1) {
	  let {a @ b @ e @ f} : bits(4*SEW) = get_velem(vs2, 4*SEW, i);
	  let {c @ d @ g @ h} : bits(4*SEW) = get_velem(vd, 4*SEW, i);
	  let MessageShedPlusC[3:0] : bits(4*SEW) = get_velem(vs1, 4*SEW, i);
	  let {W1, W0} == VSHA2cl ? MessageSchedPlusC[1:0] : MessageSchedPlusC[3:2]; // l vs h difference is the words selected

	  let T1 : bits(SEW) = h + sum1(e) + ch(e,f,g) + W0;
	  let T2 : bits(SEW) = sum0(a) + maj(a,b,c);
	  h  = g;
	  g  = f;
	  f  = e;	
	  e  = d + T1;
	  d  = c;
	  c  = b;
	  b  = a;
	  a  = T1 + T2;


	  T1  = h + sum1(e) + ch(e,f,g) + W1;
	  T2  = sum0(a) + maj(a,b,c);
	  h = g;
	  g = f;
	  f = e;	
	  e = d + T1;
	  d = c;
	  c = b;
	  b = a;
	  a = T1 + T2;
	  set_velem(vd, 4*SEW, i, {a @ b @ e @ f});
  }
  RETIRE_SUCCESS
  }
}

function sum0(x) = {
	match SEW {
		32 => rotr(x,2)  XOR rotr(x,13) XOR rotr(x,22),
		64 => rotr(x,28) XOR rotr(x,34) XOR rotr(x,39)
	}
}

function sum1(x) = {
	match SEW {
		32 => rotr(x,6)  XOR rotr(x,11) XOR rotr(x,25),
		64 => rotr(x,14) XOR rotr(x,18) XOR rotr(x,41)
	}
}

function ch(x, y, z) = ((x & y) ^ ((~x) & z))


function maj(x, y, z) =  ((x & y) ^ (x & z) ^ (y & z))

function ROTR(x,n) = (x >> n) | (x << SEW - n)

--

Included in::
<<zvkn>>, <<zvknc>>, <<zvkng>>, <<zvknh, zvknh[ab]>>
