0% found this document useful (0 votes)
41 views5 pages

ChaCha12 Algorithm Explanation

Uploaded by

vt5uzdptix
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
41 views5 pages

ChaCha12 Algorithm Explanation

Uploaded by

vt5uzdptix
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

ChaCha12 Algorithm Explanation

The ChaCha12 algorithm is a variant of the ChaCha stream cipher. It operates on a state of 16

words, each of which is 32 bits. The algorithm processes data by applying a series of

transformations called quarter-round functions. Below, we describe how ChaCha12 works and

provide sample code in C#.

1. **State Initialization**:

The state is initialized using:

- A constant string ("expand 32-byte k")

- A 256-bit key (split into 8 words)

- A 32-bit counter

- A 96-bit nonce (split into 3 words)

2. **Quarter-Round Function**:

The quarter-round function operates on four 32-bit words (A, B, C, D) as follows:

- A += B; D ^= A; D = (D << 16) | (D >> 16)

- C += D; B ^= C; B = (B << 12) | (B >> 20)

- A += B; D ^= A; D = (D << 8) | (D >> 24)

- C += D; B ^= C; B = (B << 7) | (B >> 25)

3. **Rounds**:

ChaCha12 applies 12 rounds of the quarter-round function in two alternating phases:

- Column Round: Applies the quarter-round function to the four columns of the state.

- Diagonal Round: Applies the quarter-round function to the diagonals of the state.

4. **State Addition**:
After 12 rounds, the result is added to the original state, and the keystream is extracted.

5. **Encryption**:

The plaintext is XORed with the keystream to produce the ciphertext.

C# Code for ChaCha12

using System;

class ChaCha12

private static uint RotateLeft(uint value, int shift)

return (value << shift) | (value >> (32 - shift));

private static void QuarterRound(ref uint a, ref uint b, ref uint c, ref uint d)

a += b; d ^= a; d = RotateLeft(d, 16);

c += d; b ^= c; b = RotateLeft(b, 12);

a += b; d ^= a; d = RotateLeft(d, 8);

c += d; b ^= c; b = RotateLeft(b, 7);

private static uint[] InitializeState(byte[] key, uint counter, byte[] nonce)

{
uint[] constants = new uint[] { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };

uint[] keyWords = new uint[8];

for (int i = 0; i < 8; i++)

keyWords[i] = BitConverter.ToUInt32(key, i * 4);

uint[] nonceWords = new uint[3];

for (int i = 0; i < 3; i++)

nonceWords[i] = BitConverter.ToUInt32(nonce, i * 4);

uint[] state = new uint[16];

Array.Copy(constants, 0, state, 0, 4);

Array.Copy(keyWords, 0, state, 4, 8);

state[12] = counter;

Array.Copy(nonceWords, 0, state, 13, 3);

return state;

private static void ChaCha12Rounds(ref uint[] state)

for (int i = 0; i < 6; i++)

QuarterRound(ref state[0], ref state[4], ref state[8], ref state[12]);

QuarterRound(ref state[1], ref state[5], ref state[9], ref state[13]);

QuarterRound(ref state[2], ref state[6], ref state[10], ref state[14]);

QuarterRound(ref state[3], ref state[7], ref state[11], ref state[15]);


QuarterRound(ref state[0], ref state[5], ref state[10], ref state[15]);

QuarterRound(ref state[1], ref state[6], ref state[11], ref state[12]);

QuarterRound(ref state[2], ref state[7], ref state[8], ref state[13]);

QuarterRound(ref state[3], ref state[4], ref state[9], ref state[14]);

private static void AddOriginalState(uint[] state, uint[] originalState)

for (int i = 0; i < state.Length; i++)

state[i] += originalState[i];

public static byte[] Encrypt(byte[] key, uint counter, byte[] nonce, byte[] plaintext)

byte[] ciphertext = new byte[plaintext.Length];

uint[] state = InitializeState(key, counter, nonce);

uint[] workingState = new uint[16];

byte[] keystream = new byte[64];

for (int i = 0; i < plaintext.Length; i += 64)

Array.Copy(state, workingState, 16);


ChaCha12Rounds(ref workingState);

AddOriginalState(workingState, state);

for (int j = 0; j < 16; j++)

Array.Copy(BitConverter.GetBytes(workingState[j]), 0, keystream, j * 4, 4);

for (int j = 0; j < 64 && (i + j) < plaintext.Length; j++)

ciphertext[i + j] = (byte)(plaintext[i + j] ^ keystream[j]);

state[12]++;

return ciphertext;

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy