public static Keccak CalculateHash(this BlockHeader header, RlpBehaviors behaviors = RlpBehaviors.None) { KeccakHash keccakHash = KeccakHash.Create(); KeccakRlpStream stream = new KeccakRlpStream(keccakHash); _headerDecoder.Encode(stream, header, behaviors); return(new Keccak(keccakHash.Hash)); }
public void Built_digest_short() { byte[] bytes = new byte[32]; new Random(42).NextBytes(bytes); string result = Keccak.Compute(bytes).ToString(); KeccakHash keccakHash = KeccakHash.Create(); keccakHash.Reset(); for (int i = 0; i < 1024 / 32; i += 32) { keccakHash.Update(bytes, i, 32); } Assert.AreEqual(result, keccakHash.Hash.ToHexString(true)); }
public void DeriveEncryptionParameters() { // Verify the session state is correct. if (SessionState != RLPxSessionState.AcknowledgementCompleted) { throw new Exception("RLPx encryption parameter deriviation should only occur after authentication and acknowledgement was processed."); } // Verify we have all required information if (AuthData == null || AuthAckData == null || RemoteEphermalPublicKey == null || InitiatorNonce == null || ResponderNonce == null) { throw new Exception("RLPx deriving encryption information failed: Insufficient data collected from handshake."); } // Generate the ecdh key with both ephemeral keys byte[] ecdhEphemeralKey = LocalEphemeralPrivateKey.ComputeECDHKey(RemoteEphermalPublicKey); // Generate a shared secret: Keccak256(ecdhEphemeralKey || Keccak256(ResponderNonce || InitiatorNonce)) byte[] combinedNonceHash = KeccakHash.ComputeHashBytes(ResponderNonce.Concat(InitiatorNonce)); byte[] sharedSecret = KeccakHash.ComputeHashBytes(ecdhEphemeralKey.Concat(combinedNonceHash)); // Derive the token as a hash of the shared secret. Token = KeccakHash.ComputeHashBytes(sharedSecret); // Derive AES secret: Keccak256(ecdhEphemeralKey || sharedSecret) AesSecret = KeccakHash.ComputeHashBytes(ecdhEphemeralKey.Concat(sharedSecret)); // Derive Mac secret: Keccak256(ecdhEphemeralKey || AesSecret) MacSecret = KeccakHash.ComputeHashBytes(ecdhEphemeralKey.Concat(AesSecret)); // Create our AES providers for incoming and outgoing traffic/frames. // Counter is 0, so it doesn't need to be provided, default value will handle this. IngressAes = new AesCtr(AesSecret); EgressAes = new AesCtr(AesSecret); // Next we'll want to derive our incoming (ingress) and outgoing (egress) traffic message authentication code ("MAC") // The initial state is based off of keccak((MacSecret ^ nonce) || auth/auth-ack). Later states update data from packet frames. // We begin by calculating the xor'd nonces byte[] initiatorTranformedNonce = (byte[])InitiatorNonce.Clone(); byte[] responderTransformedNonce = (byte[])ResponderNonce.Clone(); int loopSize = Math.Min(initiatorTranformedNonce.Length, MacSecret.Length); for (int i = 0; i < loopSize; i++) { initiatorTranformedNonce[i] ^= MacSecret[i]; responderTransformedNonce[i] ^= MacSecret[i]; } // Next we'll want to hash the data with our hash providers. KeccakHash initiatorOutgoing = KeccakHash.Create(); initiatorOutgoing.Update(responderTransformedNonce, 0, responderTransformedNonce.Length); initiatorOutgoing.Update(AuthData, 0, AuthData.Length); KeccakHash responderOutgoing = KeccakHash.Create(); responderOutgoing.Update(initiatorTranformedNonce, 0, initiatorTranformedNonce.Length); responderOutgoing.Update(AuthAckData, 0, AuthAckData.Length); // Assign the correct hash providers based off of role if (Role == RLPxSessionRole.Initiator) { EgressMac = initiatorOutgoing; IngressMac = responderOutgoing; } else { EgressMac = responderOutgoing; IngressMac = initiatorOutgoing; } }
public KeccakRlpStream() { KeccakHash keccakHash = KeccakHash.Create(); _keccakHash = keccakHash; }
public void TestKeccakUpdate() { // Create our random provider. Random random = new Random(); // Loop for a few test rounds. for (int i = 0; i < 5; i++) { // Generate random data byte[] bufferArray = new byte[random.Next(3, 1024 * 20)]; Span <byte> buffer = bufferArray; random.NextBytes(buffer); // Split threshold int splitThreshold = random.Next(33, 1024); // Compute the overall hash on the data byte[] singleStepHash = KeccakHash.ComputeHashBytes(buffer); // Create our keccak hash provider for multi step hash calculation. KeccakHash keccak = KeccakHash.Create(); keccak.Update(bufferArray, 0, buffer.Length); // Assert the hashes are equal Assert.Equal(singleStepHash.ToHexString(), keccak.Hash.ToHexString()); // Recompute on the same keccak instance to check if it's reusable. keccak.Reset(); keccak.Update(bufferArray, 0, buffer.Length); Assert.Equal(singleStepHash.ToHexString(), keccak.Hash.ToHexString()); // Recompute the hash but add empty array hashing. keccak.Reset(); keccak.Update(bufferArray, 0, bufferArray.Length); keccak.Update(Array.Empty <byte>(), 0, 0); keccak.Update(Array.Empty <byte>(), 0, 0); // Assert the hashes are equal Assert.Equal(singleStepHash.ToHexString(), keccak.Hash.ToHexString()); // Assert blank hashes keccak.Reset(); keccak.Update(Array.Empty <byte>(), 0, 0); keccak.Update(Array.Empty <byte>(), 0, 0); byte[] blankHash = KeccakHash.ComputeHashBytes(Array.Empty <byte>()); Assert.Equal(blankHash.ToHexString(), keccak.Hash.ToHexString()); // Refresh our new keccak instance keccak.Reset(); while (buffer.Length > 0) { // Check if this is the last round bool lastRound = buffer.Length <= splitThreshold; // Obtain the data for this round. byte[] roundData = buffer.Slice(0, lastRound ? buffer.Length : splitThreshold).ToArray(); if (lastRound) { // Obtain the final multistep hash. keccak.Update(roundData, 0, roundData.Length); // Assert the hashes are equal Assert.Equal(singleStepHash.ToHexString(), keccak.Hash.ToHexString()); // Reset keccak.Reset(); break; } else { keccak.Update(roundData, 0, roundData.Length); } // Advance our pointer. buffer = buffer.Slice(roundData.Length); } } }