[[insns-vsm4r, SM4 Block Cipher Rounds]]
= vsm4r.[vv,vs]

Synopsis::
Vector SM4 Rounds

Mnemonic::
vsm4r.vv vd, vs2 +
vsm4r.vs vd, vs2

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

Encoding (Vector-Scalar)::
[wavedrom, , svg]
....
{reg:[
{bits: 7, name: 'OP-P'},
{bits: 5, name: 'vd'},
{bits: 3, name: 'OPMVV'},
{bits: 5, name: '10000'},
{bits: 5, name: 'vs2'},
{bits: 1, name: '1'},
{bits: 6, name: '101001'},
]}
....
Reserved Encodings::
* `SEW` is any value other than 32
* Only for the `.vs` form: the `vd` register group overlaps the `vs2` register

Arguments::

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

| Vd   | input  | 128  | 4 | 32 | Current state X[0:3]
| Vs2  | input  | 128  | 4 | 32 | Round keys rk[0:3]
| Vd   | output | 128  | 4 | 32 | Next state X'[0:3]
|===

Description::
Four rounds of SM4 Encryption/Decryption are performed.

The four words of current state are read as a 4-element group from 'vd'
and the round keys are read from either the corresponding 4-element group
in `vs2` (vector-vector form) or the scalar element group in `vs2`
(vector-scalar form).
The next four words of state are generated
by iteratively XORing the last three words of the state with 
the corresponding round key, performing
a byte-wise substitution, and then performing XORs between rotated
versions of this value and the corresponding current state. 

[NOTE]
====
In SM4, encryption and decryption are identical except that decryption consumes the round keys in the reverse order.
====

[NOTE]
====
For the first  four rounds of encryption, the _current state_ is the plain text.
For the first four rounds of decryption, the _current state_ is the cipher text.
For all subsequent rounds, the _current state_ is the _next state_ from the
previous four rounds.
====

// 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,pseudocode]
--
function clause execute (VSM4R(vd, vs2)) = {
  if(LMUL*VLEN < EGW)  then {
    handle_illegal();  // illegal instruction exception
    RETIRE_FAIL
  } else {

  eg_len = (vl/EGS)
  eg_start = (vstart/EGS)
  
 let B  : bits(32) = 0;
 let S  : bits(32) = 0;
 let rk0 : bits(32) = 0;
 let rk1 : bits(32) = 0;
 let rk2 : bits(32) = 0;
 let rk3 : bits(32) = 0;
 let x0 : bits(32) = 0;
 let x1 : bits(32) = 0;
 let x2 : bits(32) = 0;
 let x3 : bits(32) = 0;
 let x4 : bits(32) = 0;
 let x5 : bits(32) = 0;
 let x6 : bits(32) = 0;
 let x7 : bits(32) = 0;

 let keyelem : bits(32) = 0;

  foreach (i from eg_start to eg_len-1) {
    keyelem = if suffix == "vv" then i else 0;
    {rk3 @ rk2 @ rk1 @ rk0} : bits(128) = get_velem(vs2, EGW=128, keyelem);
    {x3 @ x2 @ x1 @ x0} : bits(128) = get_velem(vd, EGW=128, i);

    B  = x1 ^ x2 ^ x3 ^ rk0;
    S = sm4_subword(B);
    x4 = sm4_round(x0, S);

    B = x2 ^ x3 ^ x4 ^ rk1;
    S = sm4_subword(B);
    x5= sm4_round(x1, S);

    B = x3 ^ x4 ^ x5 ^ rk2;
    S = sm4_subword(B);
    x6 = sm4_round(x2, S);

    B = x4 ^ x5 ^ x6 ^ rk3;
    S = sm4_subword(B);
    x7 = sm4_round(x3, S);

    set_velem(vd, EGW=128, i, (x7 @ x6 @ x5 @ x4));

  }
  RETIRE_SUCCESS
  }
}

val sm4_round : bits(32) -> bits(32)
function sm4_round(X, S) = \
  ((X) ^ ((S) ^ ROL32((S), 2) ^ ROL32((S), 10) ^ ROL32((S), 18) ^ ROL32((S), 24)))

--

Included in::
[%header,cols="4,2,2"]
|===
|Extension
|Minimum version
|Lifecycle state

| <<zvksed>>
| v0.1.0
| In Development
|===
