|
| 1 | +# GitHub Copilot Instructions for Int256 Repository |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +This repository contains **Nethermind.Int256**, a high-performance .NET library implementing 256-bit integer types for blockchain and cryptographic applications. The library provides both signed (`Int256`) and unsigned (`UInt256`) 256-bit integer implementations optimized for performance using hardware intrinsics and vectorization. |
| 6 | + |
| 7 | +### Key Features |
| 8 | +- **High Performance**: Leverages SIMD instructions, vectorization, and hardware intrinsics |
| 9 | +- **Complete API**: Implements all standard arithmetic, bitwise, and comparison operations |
| 10 | +- **.NET Integration**: C# with .NET 9.0 target framework, full compatibility with .NET numeric interfaces and conversion patterns |
| 11 | +- **Cross-Platform**: Supports multiple architectures with optimized code paths |
| 12 | +- **Memory Efficient**: Struct-based design with minimal allocation overhead |
| 13 | + |
| 14 | + |
| 15 | +## General |
| 16 | + |
| 17 | +- Make only high confidence suggestions when reviewing code changes. |
| 18 | +- Always use the latest version C#, currently C# 13 features. |
| 19 | +- Never change global.json unless explicitly asked to. |
| 20 | +- Never change package.json or package-lock.json files unless explicitly asked to. |
| 21 | +- Never change NuGet.config files unless explicitly asked to. |
| 22 | +- Always trim trailing whitespace, and do not have whitespace on otherwise empty lines. |
| 23 | + |
| 24 | +**Any code you commit SHOULD compile, and new and existing tests related to the change SHOULD pass.** |
| 25 | + |
| 26 | +You MUST make your best effort to ensure your changes satisfy those criteria before committing. If for any reason you were unable to build or test the changes, you MUST report that. You MUST NOT claim success unless all builds and tests pass as described above. |
| 27 | + |
| 28 | +You MUST follow all code-formatting and naming conventions defined in [`.editorconfig`](/.editorconfig). |
| 29 | + |
| 30 | +In addition to the rules enforced by `.editorconfig`, you SHOULD: |
| 31 | + |
| 32 | +- Prefer file-scoped namespace declarations and single-line using directives; however do not change the type of namespace format in an existing file unless specifically asked. |
| 33 | +- Ensure that the final return statement of a method is on its own line. |
| 34 | +- Use pattern matching and switch expressions wherever possible. |
| 35 | +- Use `nameof` instead of string literals when referring to member names. |
| 36 | +- Always use `is null` or `is not null` instead of `== null` or `!= null`. |
| 37 | +- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null. |
| 38 | +- Prefer `?.` if applicable (e.g. `scope?.Dispose()`). |
| 39 | +- Use `ObjectDisposedException.ThrowIf` where applicable. |
| 40 | +- When adding new unit tests, strongly prefer to add them to existing test code files rather than creating new code files. |
| 41 | +- If you add new code files, ensure they are listed in the csproj file (if other files in that folder are listed there) so they build. |
| 42 | +- When running tests, if possible use filters and check test run counts, or look at test logs, to ensure they actually ran. |
| 43 | +- Do not finish work with any tests commented out or disabled that were not previously commented out or disabled. |
| 44 | +- When writing tests, do not emit "Act", "Arrange" or "Assert" comments. |
| 45 | +- Copy existing style in nearby files for test method names and capitalization. |
| 46 | +- Provide code comments when helpful to explain why something is being done; however do not comment what is obvious and just a repeation of the code line. |
| 47 | +- Ensure that XML doc comments are created for any public APIs. |
| 48 | +- Do NOT use #regions. |
| 49 | +- Prefer low allocation and higher performance code. |
| 50 | + |
| 51 | +--- |
| 52 | + |
| 53 | + |
| 54 | +## Architecture and Core Components |
| 55 | + |
| 56 | +### Core Types |
| 57 | +- **`UInt256`**: 256-bit unsigned integer (primary implementation) |
| 58 | +- **`Int256`**: 256-bit signed integer (wrapper around UInt256) |
| 59 | +- **`IInteger<T>`**: Common interface for integer operations |
| 60 | +- **`BigIntegerExtensions`**: Extensions for System.Numerics.BigInteger integration |
| 61 | + |
| 62 | +### Internal Structure |
| 63 | +```csharp |
| 64 | +// UInt256 uses explicit layout with 4 ulong components |
| 65 | +[StructLayout(LayoutKind.Explicit)] |
| 66 | +public readonly struct UInt256 |
| 67 | +{ |
| 68 | + [FieldOffset(0)] public readonly ulong u0; // Least significant |
| 69 | + [FieldOffset(8)] public readonly ulong u1; |
| 70 | + [FieldOffset(16)] public readonly ulong u2; |
| 71 | + [FieldOffset(24)] public readonly ulong u3; // Most significant |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +### Performance Optimizations |
| 76 | +- **Hardware Intrinsics**: Uses `Vector256<T>` when available |
| 77 | +- **Conditional Compilation**: Hardware intrinsics can be disabled via `DOTNET_EnableHWIntrinsic=0` |
| 78 | +- **Unsafe Operations**: Leverages unsafe code for optimal performance |
| 79 | +- **Branch Optimization**: Minimizes conditional branches in hot paths |
| 80 | + |
| 81 | +## Development Environment |
| 82 | + |
| 83 | +### Requirements |
| 84 | +- **.NET 9.0 SDK** (specified in global.json) |
| 85 | +- **Visual Studio 2022** or **VS Code** with C# extension |
| 86 | +- **Git** for version control |
| 87 | + |
| 88 | +### Project Structure |
| 89 | +``` |
| 90 | +src/ |
| 91 | +├── Nethermind.Int256/ # Core library |
| 92 | +│ ├── Int256.cs # Signed 256-bit integer |
| 93 | +│ ├── UInt256.cs # Unsigned 256-bit integer (main implementation) |
| 94 | +│ ├── IInteger.cs # Common interface |
| 95 | +│ └── BigIntegerExtensions.cs # BigInteger helpers |
| 96 | +├── Nethermind.Int256.Tests/ # Unit tests |
| 97 | +└── Nethermind.Int256.Benchmark/ # Performance benchmarks |
| 98 | +``` |
| 99 | + |
| 100 | +### Build Commands |
| 101 | +```bash |
| 102 | +# Restore dependencies |
| 103 | +dotnet restore |
| 104 | + |
| 105 | +# Build (from src directory) |
| 106 | +dotnet build |
| 107 | + |
| 108 | +# Run tests |
| 109 | +dotnet run -c Debug --project src/Nethermind.Int256.Tests |
| 110 | + |
| 111 | +# Run benchmarks |
| 112 | +dotnet run -c Release --project src/Nethermind.Int256.Benchmark |
| 113 | +``` |
| 114 | + |
| 115 | +## Coding Standards and Conventions |
| 116 | + |
| 117 | +### Code Style |
| 118 | +- **Latest C# Language Version**: Uses `<LangVersion>latest</LangVersion>` |
| 119 | +- **Nullable Reference Types**: Enabled throughout the project |
| 120 | +- **Unsafe Blocks**: Allowed for performance-critical sections |
| 121 | +- **Warnings as Errors**: `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>` |
| 122 | +- **Formatting**: 4-space indentation for C# files, LF line endings, UTF-8 encoding |
| 123 | +- **Interface Naming**: Interfaces should begin with 'I' (e.g., `IInteger<T>`) |
| 124 | +- **Type Naming**: PascalCase for types, methods, and properties |
| 125 | + |
| 126 | +### Naming Conventions |
| 127 | +- **Internal Fields**: Use `u0, u1, u2, u3` for UInt256 components (little-endian order) |
| 128 | +- **Constants**: Use PascalCase (e.g., `MaxValue`, `MinValue`) |
| 129 | +- **Static Readonly**: Use for compile-time constants |
| 130 | +- **Private Static**: Use `s_` prefix for static fields (e.g., `s_instanceRandom`) |
| 131 | + |
| 132 | +### Performance Guidelines |
| 133 | +1. **Prefer Struct Operations**: Avoid boxing/unboxing |
| 134 | +2. **Use ReadOnlySpan<T>**: For byte array operations |
| 135 | +3. **Leverage Vector Operations**: When `Vector256<T>.IsSupported` |
| 136 | +4. **Minimize Allocations**: Use `Unsafe.SkipInit()` when appropriate |
| 137 | +5. **Branch Optimization**: Structure code to minimize conditional branches |
| 138 | + |
| 139 | +### Memory Layout Considerations |
| 140 | +```csharp |
| 141 | +// Always consider endianness |
| 142 | +public UInt256(ReadOnlySpan<byte> bytes, bool isBigEndian) |
| 143 | + |
| 144 | +// Use explicit field offsets for predictable layout |
| 145 | +[FieldOffset(0)] public readonly ulong u0; // Little-endian: LSB first |
| 146 | +``` |
| 147 | + |
| 148 | +## Testing Guidelines |
| 149 | + |
| 150 | +### Test Organization |
| 151 | +- **Unit Tests**: Located in `Nethermind.Int256.Tests` |
| 152 | +- **Test Categories**: Organized by operation type (Binary, Unary, Ternary, Convertibles) |
| 153 | +- **Hardware Intrinsics Testing**: Tests run with both enabled and disabled intrinsics |
| 154 | +- **Template Pattern**: Uses `UInt256TestsTemplate<T>` for shared test logic |
| 155 | +- **FluentAssertions**: Uses FluentAssertions for readable test assertions |
| 156 | +- **NUnit Framework**: All tests use NUnit attributes and framework |
| 157 | + |
| 158 | +### Test Naming |
| 159 | +```csharp |
| 160 | +[Test] |
| 161 | +public void OperationName_Scenario_ExpectedResult() |
| 162 | +{ |
| 163 | + // Arrange, Act, Assert pattern |
| 164 | + // Use FluentAssertions for readable assertions |
| 165 | + result.Should().Be(expected); |
| 166 | +} |
| 167 | + |
| 168 | +[TestCaseSource(typeof(BinaryOps), nameof(BinaryOps.TestCases))] |
| 169 | +public void Add((BigInteger A, BigInteger B) test) |
| 170 | +{ |
| 171 | + // Use test case sources for comprehensive testing |
| 172 | +} |
| 173 | +``` |
| 174 | + |
| 175 | +### Test Data |
| 176 | +- **TestNumbers.cs**: Contains predefined test values and edge cases |
| 177 | +- **Comprehensive Coverage**: Tests include overflow, underflow, and boundary conditions |
| 178 | +- **Cross-Platform**: Tests verify behavior across different hardware configurations |
| 179 | + |
| 180 | +### Writing New Tests |
| 181 | +When adding operations, ensure tests cover: |
| 182 | +1. **Basic Operations**: Normal cases with typical values |
| 183 | +2. **Edge Cases**: Zero, maximum/minimum values, overflow conditions |
| 184 | +3. **Conversion Tests**: To/from other numeric types |
| 185 | +4. **Performance Tests**: For critical path operations |
| 186 | + |
| 187 | +## Performance Considerations |
| 188 | + |
| 189 | +### Optimization Priorities |
| 190 | +1. **Hot Path Operations**: Arithmetic operations (+, -, *, /, %) |
| 191 | +2. **Comparison Operations**: Equality, less than, greater than |
| 192 | +3. **Bitwise Operations**: AND, OR, XOR, shifts |
| 193 | +4. **Conversion Operations**: To/from BigInteger, primitive types |
| 194 | + |
| 195 | +### Hardware Intrinsics Usage |
| 196 | +```csharp |
| 197 | +if (Vector256<uint>.IsSupported) |
| 198 | +{ |
| 199 | + // Use vectorized operations |
| 200 | + Unsafe.As<ulong, Vector256<uint>>(ref this.u0) = Vector256.Create(...); |
| 201 | +} |
| 202 | +else |
| 203 | +{ |
| 204 | + // Fallback to scalar operations |
| 205 | +} |
| 206 | +``` |
| 207 | + |
| 208 | +### Memory Access Patterns |
| 209 | +- **Sequential Access**: Prefer when possible for cache efficiency |
| 210 | +- **Alignment**: Struct layout ensures proper alignment |
| 211 | +- **Avoid Indirection**: Direct field access over property chains |
| 212 | + |
| 213 | +## Build and CI Process |
| 214 | + |
| 215 | +### GitHub Actions Workflow |
| 216 | +- **Matrix Testing**: Tests against Debug/Release builds |
| 217 | +- **Hardware Intrinsics**: Tests with `DOTNET_EnableHWIntrinsic=0` and `=1` |
| 218 | +- **Cross-Platform**: Linux-based testing environment |
| 219 | +- **NuGet Publishing**: Automated on releases |
| 220 | + |
| 221 | +### Local Development |
| 222 | +```bash |
| 223 | +# Run full test matrix locally |
| 224 | +DOTNET_EnableHWIntrinsic=0 dotnet run -c Debug --project src/Nethermind.Int256.Tests |
| 225 | +DOTNET_EnableHWIntrinsic=1 dotnet run -c Release --project src/Nethermind.Int256.Tests |
| 226 | + |
| 227 | +# Run performance benchmarks |
| 228 | +dotnet run -c Release --project src/Nethermind.Int256.Benchmark |
| 229 | +``` |
| 230 | + |
| 231 | +### Benchmarking |
| 232 | +- **BenchmarkDotNet**: Uses BenchmarkDotNet for performance testing |
| 233 | +- **Hardware Variants**: Benchmarks test both with and without hardware intrinsics |
| 234 | +- **Baseline Comparisons**: Compare against System.Numerics.BigInteger where applicable |
| 235 | + |
| 236 | +### Package Configuration |
| 237 | +- **Package ID**: `Nethermind.Numerics.Int256` |
| 238 | +- **Target Framework**: net9.0 |
| 239 | +- **Dependencies**: Minimal (Microsoft.SourceLink.GitHub for debugging) |
| 240 | + |
| 241 | +## Common Patterns and Examples |
| 242 | + |
| 243 | +### Creating UInt256 Values |
| 244 | +```csharp |
| 245 | +// From primitive types |
| 246 | +UInt256 value1 = 42ul; |
| 247 | +UInt256 value2 = new UInt256(0x12345678, 0x9ABCDEF0, 0, 0); |
| 248 | + |
| 249 | +// From byte array |
| 250 | +var bytes = new byte[32]; |
| 251 | +UInt256 value3 = new UInt256(bytes, isBigEndian: true); |
| 252 | + |
| 253 | +// From BigInteger |
| 254 | +BigInteger big = BigInteger.Parse("123456789012345678901234567890"); |
| 255 | +UInt256 value4 = (UInt256)big; |
| 256 | +``` |
| 257 | + |
| 258 | +### Arithmetic Operations |
| 259 | +```csharp |
| 260 | +UInt256 a = 100; |
| 261 | +UInt256 b = 200; |
| 262 | +UInt256 sum = a + b; |
| 263 | +UInt256 product = a * b; |
| 264 | +bool isEqual = a == b; |
| 265 | +``` |
| 266 | + |
| 267 | +### Performance-Critical Code Patterns |
| 268 | +```csharp |
| 269 | +// Use in/out parameters to avoid copies |
| 270 | +public static void Add(in UInt256 left, in UInt256 right, out UInt256 result) |
| 271 | + |
| 272 | +// Leverage hardware intrinsics when available |
| 273 | +if (Vector256<ulong>.IsSupported) |
| 274 | +{ |
| 275 | + // Vectorized implementation |
| 276 | +} |
| 277 | +else |
| 278 | +{ |
| 279 | + // Scalar fallback |
| 280 | +} |
| 281 | + |
| 282 | +// Follow the IInteger<T> interface pattern for consistency |
| 283 | +public void Add(in T a, out T res) |
| 284 | +{ |
| 285 | + // Implementation |
| 286 | +} |
| 287 | +``` |
| 288 | + |
| 289 | +## Contributing Guidelines |
| 290 | + |
| 291 | +### License and Copyright |
| 292 | +- **License**: MIT License (see LICENSE file) |
| 293 | +- **Copyright**: Demerzel Solutions Limited |
| 294 | + |
| 295 | +### Before Making Changes |
| 296 | +1. **Understand Performance Impact**: Profile changes affecting hot paths |
| 297 | +2. **Test Hardware Variants**: Ensure compatibility with/without intrinsics |
| 298 | +3. **Maintain API Compatibility**: Preserve existing public interfaces |
| 299 | +4. **Follow Existing Patterns**: Consistency with established code style |
| 300 | + |
| 301 | +### Code Review Focus Areas |
| 302 | +- **Performance**: No regression in benchmark results |
| 303 | +- **Correctness**: Comprehensive test coverage |
| 304 | +- **Security**: Proper handling of edge cases and overflow |
| 305 | +- **Maintainability**: Clear, readable implementation |
| 306 | + |
| 307 | +--- |
| 308 | + |
| 309 | +This library is a critical component for blockchain and cryptographic applications where performance and correctness are paramount. Always prioritize these concerns when making contributions. |
| 310 | + |
| 311 | +## Quick Reference |
| 312 | + |
| 313 | +### Key Files to Understand |
| 314 | +- `UInt256.cs` - Primary implementation with all core operations |
| 315 | +- `Int256.cs` - Signed wrapper around UInt256 |
| 316 | +- `IInteger.cs` - Common interface defining operation patterns |
| 317 | +- `TestNumbers.cs` - Constants and edge cases for testing |
| 318 | + |
| 319 | +### Common Operations Pattern |
| 320 | +```csharp |
| 321 | +// All operations follow this pattern for consistency and performance |
| 322 | +public void OperationName(in UInt256 other, out UInt256 result) |
| 323 | +{ |
| 324 | + // Implementation using 'in' parameters to avoid copies |
| 325 | + // and 'out' parameters for results |
| 326 | +} |
| 327 | +``` |
0 commit comments