Skip to content

Rewrite Base64/Base64Url helpers without unsafe code - #134548

Draft
EgorBo wants to merge 2 commits into
dotnet:mainfrom
EgorBo:base64-safe
Draft

EgorBo wants to merge 2 commits into
dotnet:mainfrom
EgorBo:base64-safe

Conversation

@EgorBo

@EgorBo EgorBo commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Just an AI attempt to rewrite base64 to 100% safe code.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a672b164-caaf-4b6f-93d8-6089357964e8
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-buffers
See info in area-owners.md if you want to be subscribed.

@EgorBo

EgorBo commented Sep 23, 2026

Copy link
Copy Markdown
Member Author

@EgorBot -linux_amd -linux_intel -osx_arm64

using System.Buffers.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);

public class Bench {
    private byte[] _data = default!, _utf8 = default!;

    [Params(16, 32, 64, 150, 256, 1500, 4096, 16384, 65536)]
    public int Size { get; set; }

    [GlobalSetup]
    public void Setup() {
        _data = new byte[Size];
        new Random(42).NextBytes(_data);
        _utf8 = new byte[Base64.GetEncodedLength(Size)];
    }

    [Benchmark] public int B64_EncodeToUtf8() => Base64.EncodeToUtf8(_data, _utf8);
    [Benchmark] public int Url_EncodeToUtf8() => Base64Url.EncodeToUtf8(_data, _utf8);
    [Benchmark] public string Convert_ToBase64String() => Convert.ToBase64String(_data);
    [Benchmark] public string Url_EncodeToString() => Base64Url.EncodeToString(_data);
}

Note

This benchmark was generated with Copilot.

@EgorBo

EgorBo commented Sep 23, 2026

Copy link
Copy Markdown
Member Author

@EgorBot -linux_amd -linux_intel -osx_arm64

using System.Buffers.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);

public class Bench {
    private byte[] _b64 = default!, _url = default!, _dest = default!;
    private string _b64String = default!, _urlString = default!;

    [Params(16, 32, 64, 150, 256, 1500, 4096, 16384, 65536)]
    public int Size { get; set; }

    [GlobalSetup]
    public void Setup() {
        byte[] data = new byte[Size];
        new Random(42).NextBytes(data);
        _b64String = Convert.ToBase64String(data);
        _b64 = System.Text.Encoding.ASCII.GetBytes(_b64String);
        _urlString = Base64Url.EncodeToString(data);
        _url = Base64Url.EncodeToUtf8(data);
        _dest = new byte[Size];
    }

    [Benchmark] public int B64_DecodeFromUtf8() => Base64.DecodeFromUtf8(_b64, _dest);
    [Benchmark] public int Url_DecodeFromUtf8() => Base64Url.DecodeFromUtf8(_url, _dest);
    [Benchmark] public byte[] Convert_FromBase64String() => Convert.FromBase64String(_b64String);
    [Benchmark] public int Url_DecodeFromChars() => Base64Url.DecodeFromChars(_urlString, _dest);
}

Note

This benchmark was generated with Copilot.

@EgorBo

EgorBo commented Sep 23, 2026

Copy link
Copy Markdown
Member Author

@EgorBot -linux_amd -linux_intel -osx_arm64

using System.Buffers.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);

public class Bench {
    private byte[] _data = default!, _b64 = default!, _url = default!, _buffer = default!;

    [Params(16, 32, 64, 150, 256, 1500, 4096, 16384, 65536)]
    public int Size { get; set; }

    [GlobalSetup]
    public void Setup() {
        _data = new byte[Size];
        new Random(42).NextBytes(_data);
        _b64 = System.Text.Encoding.ASCII.GetBytes(Convert.ToBase64String(_data));
        _url = Base64Url.EncodeToUtf8(_data);
        _buffer = new byte[Base64.GetEncodedLength(Size)];
    }

    [Benchmark]
    public int B64_EncodeInPlace() {
        _data.CopyTo(_buffer, 0);
        Base64.EncodeToUtf8InPlace(_buffer, _data.Length, out int written);
        return written;
    }

    [Benchmark]
    public int Url_EncodeInPlace() {
        _data.CopyTo(_buffer, 0);
        Base64Url.TryEncodeToUtf8InPlace(_buffer, _data.Length, out int written);
        return written;
    }

    [Benchmark]
    public int B64_DecodeInPlace() {
        _b64.CopyTo(_buffer, 0);
        Base64.DecodeFromUtf8InPlace(_buffer.AsSpan(0, _b64.Length), out int written);
        return written;
    }

    [Benchmark]
    public int Url_DecodeInPlace() {
        _url.CopyTo(_buffer, 0);
        return Base64Url.DecodeFromUtf8InPlace(_buffer.AsSpan(0, _url.Length));
    }
}

Note

This benchmark was generated with Copilot.

- Unroll AVX-512 encode/decode loops x2
- Register-based forward encode for small in-place inputs
- Span-flow in-place decode, fewer bounds checks in tail writes
- Compute scalar encode indices directly from the bytes
- Inline Base64Url.GetEncodedLength/GetMaxDecodedLength

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a672b164-caaf-4b6f-93d8-6089357964e8
@EgorBo

EgorBo commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

@EgorBot -linux_amd -linux_intel -osx_arm64

using System.Buffers.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);

public class Bench {
    private byte[] _data = default!, _utf8 = default!;

    [Params(16, 32, 64, 150, 256, 1500, 4096, 16384, 65536)]
    public int Size { get; set; }

    [GlobalSetup]
    public void Setup() {
        _data = new byte[Size];
        new Random(42).NextBytes(_data);
        _utf8 = new byte[Base64.GetEncodedLength(Size)];
    }

    [Benchmark] public int B64_EncodeToUtf8() => Base64.EncodeToUtf8(_data, _utf8);
    [Benchmark] public int Url_EncodeToUtf8() => Base64Url.EncodeToUtf8(_data, _utf8);
    [Benchmark] public string Convert_ToBase64String() => Convert.ToBase64String(_data);
    [Benchmark] public string Url_EncodeToString() => Base64Url.EncodeToString(_data);
}

@EgorBo

EgorBo commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

@EgorBot -linux_amd -linux_intel -osx_arm64

using System.Buffers.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);

public class Bench {
    private byte[] _b64 = default!, _url = default!, _dest = default!;
    private string _b64String = default!, _urlString = default!;

    [Params(16, 32, 64, 150, 256, 1500, 4096, 16384, 65536)]
    public int Size { get; set; }

    [GlobalSetup]
    public void Setup() {
        byte[] data = new byte[Size];
        new Random(42).NextBytes(data);
        _b64String = Convert.ToBase64String(data);
        _b64 = System.Text.Encoding.ASCII.GetBytes(_b64String);
        _urlString = Base64Url.EncodeToString(data);
        _url = Base64Url.EncodeToUtf8(data);
        _dest = new byte[Size];
    }

    [Benchmark] public int B64_DecodeFromUtf8() => Base64.DecodeFromUtf8(_b64, _dest);
    [Benchmark] public int Url_DecodeFromUtf8() => Base64Url.DecodeFromUtf8(_url, _dest);
    [Benchmark] public byte[] Convert_FromBase64String() => Convert.FromBase64String(_b64String);
    [Benchmark] public int Url_DecodeFromChars() => Base64Url.DecodeFromChars(_urlString, _dest);
}

Note

This benchmark was generated with Copilot.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant